<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Posts on Mike&#39;s Software Blog</title>
        <link>https://mike42.me/blog/post</link>
        <description>Recent content in Posts on Mike&#39;s Software Blog</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>en</language>
        <copyright>Michael Billington</copyright>
        <lastBuildDate>Tue, 30 Dec 2025 15:21:59 +1100</lastBuildDate><atom:link href="https://mike42.me/blog/post/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>Farewell, wordpress!</title>
        <link>https://mike42.me/blog/2025-12-farewell-wordpress</link>
        <pubDate>Mon, 29 Dec 2025 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2025-12-farewell-wordpress</guid>
        <description>&lt;p&gt;I&amp;rsquo;ve recently re-built this blog using the static site generator, Hugo. This post is a few notes about the motivations and challenges behind that.&lt;/p&gt;



&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-tabs-2018-03-new-wordpress-theme-2018-edition&#34;
      id=&#34;tabs-tabs-2018-03-new-wordpress-theme-2018-edition-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-tabs-2018-03-new-wordpress-theme-2018-edition-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Old theme
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-08-custom-wordpress-theme.png&#34;
	width=&#34;3562&#34;
	height=&#34;2060&#34;
	srcset=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-08-custom-wordpress-theme_hu_4bef372fcbaac0d1.png 480w, https://mike42.me/blog/2025-12-farewell-wordpress/2025-08-custom-wordpress-theme_hu_c422d8cccc585600.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;172&#34;
		data-flex-basis=&#34;414px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-tabs-2018-03-new-wordpress-theme-2018-edition&#34;
      id=&#34;tabs-tabs-2018-03-new-wordpress-theme-2018-edition-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-tabs-2018-03-new-wordpress-theme-2018-edition-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      New theme
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-08-customised-hugo-stack-theme.png&#34;
	width=&#34;3562&#34;
	height=&#34;2060&#34;
	srcset=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-08-customised-hugo-stack-theme_hu_4619121a20085e04.png 480w, https://mike42.me/blog/2025-12-farewell-wordpress/2025-08-customised-hugo-stack-theme_hu_95065566c09c6bfe.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;172&#34;
		data-flex-basis=&#34;414px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-tabs-2018-03-new-wordpress-theme-2018-edition&#34;
      id=&#34;tabs-tabs-2018-03-new-wordpress-theme-2018-edition-2&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-tabs-2018-03-new-wordpress-theme-2018-edition-2&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      New theme (dark mode)
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-08-customised-hugo-stack-theme-dark.png&#34;
	width=&#34;3562&#34;
	height=&#34;2060&#34;
	srcset=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-08-customised-hugo-stack-theme-dark_hu_59435c0bd7f809a6.png 480w, https://mike42.me/blog/2025-12-farewell-wordpress/2025-08-customised-hugo-stack-theme-dark_hu_d6f245e29e5a7687.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;172&#34;
		data-flex-basis=&#34;414px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2 id=&#34;why-wordpress-had-to-go&#34;&gt;Why Wordpress had to go
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;ve maintained some sort of blog since 2007. I&amp;rsquo;ve mainly hosted it on Wordpress, but also switched to a custom blog engine for a few years there.&lt;/p&gt;
&lt;h3 id=&#34;editing-experience&#34;&gt;Editing experience
&lt;/h3&gt;&lt;p&gt;One reason I considered switching away from Wordpress was that it was becoming tedious to use it for the type of writing I do.&lt;/p&gt;
&lt;p&gt;I usually post technical notes which I&amp;rsquo;ve written in markdown (&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v/&#34; &gt;typical example&lt;/a&gt;), and support for that has changed over the years. I&amp;rsquo;ve most recently been using Jetpack&amp;rsquo;s markdown support, but previously used a standalone Wordpress plugin for markdown support, and also had plenty of posts marked up in HTML directly.&lt;/p&gt;
&lt;p&gt;I needed to re-do the theme because it was starting to show its age, but at this point, editing old content would randomly break things.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-08-wordpress-markdown-example.png&#34;
	width=&#34;1375&#34;
	height=&#34;795&#34;
	srcset=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-08-wordpress-markdown-example_hu_6bf343acecb9571f.png 480w, https://mike42.me/blog/2025-12-farewell-wordpress/2025-08-wordpress-markdown-example_hu_1b935ecf8a89b812.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;172&#34;
		data-flex-basis=&#34;415px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-08-wordpress-markdown-setting.png&#34;
	width=&#34;1439&#34;
	height=&#34;800&#34;
	srcset=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-08-wordpress-markdown-setting_hu_3278b135063443e3.png 480w, https://mike42.me/blog/2025-12-farewell-wordpress/2025-08-wordpress-markdown-setting_hu_dbcd146203760acf.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;179&#34;
		data-flex-basis=&#34;431px&#34;
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;the-ai-elephant-in-the-room&#34;&gt;The AI elephant in the room
&lt;/h3&gt;&lt;p&gt;It was really the rise of AI crawlers that killed Wordpress for me. This website is a lean self-hosted setup with a few small apps - not just a blog - and the huge volume of crawler traffic was causing the mariadb database behind Wordpress to run out of memory.&lt;/p&gt;
&lt;p&gt;The crawler behaviour I observed was positively unhinged, aside from showing no consideration for resource usage. For now the main change I am making will be to serve this blog entirely from static files, since it will improve resilience to traffic spikes in general.&lt;/p&gt;
&lt;p&gt;I didn&amp;rsquo;t record specific data on the web crawler traffic in my case, but this &lt;a class=&#34;link&#34; href=&#34;https://news.ycombinator.com/item?id=45105230&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;HackerNews thread&lt;/a&gt; has some sysadmins who are experiencing similar issues.&lt;/p&gt;
&lt;h2 id=&#34;making-the-switch&#34;&gt;Making the switch
&lt;/h2&gt;&lt;p&gt;I chose Hugo because, among widely-used static side generators, it has the strong differentiator of being runnable as a single binary file. It was not a perfect fit though, and I needed to customise a few things.&lt;/p&gt;
&lt;h3 id=&#34;preserving-urls&#34;&gt;Preserving URLs
&lt;/h3&gt;&lt;p&gt;I am bringing across a back catalogue of posts, and I want to continue to serve pages from the same URLs as before.&lt;/p&gt;
&lt;p&gt;Hugo adds a trailing slash on the end of URLs, which does not match my existing scheme, and this behaviour is frustratingly difficult to override.&lt;/p&gt;
&lt;p&gt;I took inspiration from one of the many threads about this on the Hugo forums.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Fortunately I did come up with a solution in the end by overriding rel and relref to trim the trailing slash for all URLs except for the ones I wanted to keep the / on.&amp;rdquo; - &lt;a class=&#34;link&#34; href=&#34;https://discourse.gohugo.io/t/situationally-removing-trailing-slashes-in-urls-yes-i-read-every-thread/50865&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;nickjanetakis on the Hugo forums&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;I decided to implement this tip by forking the theme I&amp;rsquo;m using, which in my case is &lt;a class=&#34;link&#34; href=&#34;https://github.com/CaiJimmy/hugo-theme-stack&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;CaiJimmy/hugo-theme-stack&lt;/a&gt;, and editing any part that produces links. There&amp;rsquo;s a bit more to it, but it is mostly a lot of changes like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gh&#34;&gt;diff --git a/themes/hugo-theme-stack/layouts/partials/article-list/tile.html b/themes/hugo-theme-stack/layouts/partials/article-list/tile.html
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gh&#34;&gt;index be5744b..c8219fd 100644
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gh&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;--- a/themes/hugo-theme-stack/layouts/partials/article-list/tile.html
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+++ b/themes/hugo-theme-stack/layouts/partials/article-list/tile.html
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;@@ -1,6 +1,6 @@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt; {{ $image := partialCached &amp;#34;helper/image&amp;#34; (dict &amp;#34;Context&amp;#34; .context &amp;#34;Type&amp;#34; .Type) .context.RelPermalink .Type }}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &amp;lt;article class=&amp;#34;{{ if $image.exists }}has-image{{ end }}&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gd&#34;&gt;-    &amp;lt;a href=&amp;#34;{{ .context.RelPermalink }}&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+    &amp;lt;a href=&amp;#34;{{ .context.RelPermalink | strings.TrimSuffix &amp;#34;/&amp;#34; }}&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;         
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         {{ if $image.exists }}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             &amp;lt;div class=&amp;#34;article-image&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I also found default templates in the Hugo source code for rendering RSS feeds and sitemaps, copied them into the theme, and made similar changes.&lt;/p&gt;
&lt;p&gt;In my case I&amp;rsquo;m running Apache, and this is the first part of the &lt;code&gt;.htaccess&lt;/code&gt; for my &lt;code&gt;/blog/&lt;/code&gt; directory, which configures it to serve pages without the trailing slash among other fixes.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# Send to Hugo 404 page
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ErrorDocument 404 /blog/404.html
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# Do not add slashes to dir names
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;DirectorySlash Off
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# Use mod_rewrite to provide other redirects
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;RewriteEngine On
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;RewriteBase /blog/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# Redirect trailing-slash URLs to non-trailing-slash URL
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;RewriteCond %{REQUEST_FILENAME} -d
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;RewriteRule ^(.*)/$ $1 [R=301,L]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# Serve blog content when given dir name w/o trailing slash
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;RewriteCond %{REQUEST_FILENAME} -d
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;RewriteRule ^(.*)$ %{REQUEST_URI}/index.html [L]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# Redirect old AMP URL&amp;#39;s back to where canonical page would be (note: we do not check here if the page actually exists)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;RewriteCond %{REQUEST_URI} ^(.*)/amp$
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;RewriteRule ^(.*)/amp$ $1 [R=301]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;exporting-the-content&#34;&gt;Exporting the content
&lt;/h3&gt;&lt;p&gt;I needed to port approximately 200 blog posts to from a live Wordpress to Hugo.&lt;/p&gt;
&lt;p&gt;I saved every blog post to disk using Wordpress&amp;rsquo;s &lt;a class=&#34;link&#34; href=&#34;https://learn.wordpress.org/tutorial/tools-import-and-export/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;built-in export&lt;/a&gt;, which produces an extended RSS file containing HTML markup and metadata.&lt;/p&gt;
&lt;p&gt;I combined this with the image site map, and with the help of some Python, was able to produce a directory for each post containing front matter, text and images.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-07-html-representation-of-blog-content.png&#34;
	width=&#34;1728&#34;
	height=&#34;897&#34;
	srcset=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-07-html-representation-of-blog-content_hu_45d4d3f3e5e61602.png 480w, https://mike42.me/blog/2025-12-farewell-wordpress/2025-07-html-representation-of-blog-content_hu_f7ab2e9d5261d6f6.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;A blog post exported from Wordpress with correct metadata but HTML content&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;192&#34;
		data-flex-basis=&#34;462px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I then also made a Wordpress database dump, imported on my desktop, and dumped the &lt;code&gt;wp_posts&lt;/code&gt; table to JSON. This gave me access to the markdown representation of the article where it exists, via the &lt;code&gt;post_content_filtered&lt;/code&gt; column in this table.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-07-blog-to-json.png&#34;
	width=&#34;1783&#34;
	height=&#34;762&#34;
	srcset=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-07-blog-to-json_hu_7591b950d067b7e.png 480w, https://mike42.me/blog/2025-12-farewell-wordpress/2025-07-blog-to-json_hu_8d37942b4d827bb9.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Extracting markdown from an exported Wordpress database&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;233&#34;
		data-flex-basis=&#34;561px&#34;
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;the-8020-rule&#34;&gt;The 80/20 rule
&lt;/h3&gt;&lt;p&gt;Most of the blog content was intelligible at this point, but I still needed to do a time-consuming walk through of each blog post to check and correct the markup, so that it would properly use the theme&amp;rsquo;s features.&lt;/p&gt;
&lt;p&gt;Just some of the examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Some blog posts place content in tabs, such as &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/&#34; &gt;What is ESC/POS, and how do I use it?&lt;/a&gt;. I borrowed the tab implementation from the &lt;a class=&#34;link&#34; href=&#34;https://github.com/thegeeklab/hugo-geekdoc&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Geekdoc&lt;/a&gt; theme.&lt;/li&gt;
&lt;li&gt;Images and code blocks had been consistently included using HTML &lt;code&gt;&amp;lt;code&amp;gt;&lt;/code&gt; blocks before. I could mostly fix these with find/replace patterns.&lt;/li&gt;
&lt;li&gt;Many blog posts were fully or partly written in HTML and needed to be converted to Markdown. Again this was mostly find/replace.&lt;/li&gt;
&lt;li&gt;Some blog posts used raw blobs of HTML which cannot be represented in markdown, such as &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2011-08-some-scripts-to-make-word-puzzles&#34; &gt;Some scripts to make word puzzles&lt;/a&gt;. I &lt;a class=&#34;link&#34; href=&#34;https://anaulin.org/blog/hugo-raw-html-shortcode/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;added a shortcode for raw HTML&lt;/a&gt;, and spent some time updating these pages to work with light/dark theming.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;remaining-issues&#34;&gt;Remaining issues
&lt;/h2&gt;&lt;h3 id=&#34;dark-mode-and-transparency&#34;&gt;Dark mode and transparency
&lt;/h3&gt;&lt;p&gt;The new styling is an improvement, but there are graphics with transparent backgrounds in my existing content which are difficult to see in dark mode, or when opened up in the image gallery view.&lt;/p&gt;
&lt;p&gt;An example would be the circuit diagram in the screen captures below.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-11-29-diagram-on-light.png&#34;
	width=&#34;4778&#34;
	height=&#34;2670&#34;
	srcset=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-11-29-diagram-on-light_hu_ea21dc9ac383b49c.png 480w, https://mike42.me/blog/2025-12-farewell-wordpress/2025-11-29-diagram-on-light_hu_e017ce210c96a201.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Light mode&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;178&#34;
		data-flex-basis=&#34;429px&#34;
	
&gt; &lt;img src=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-11-29-diagram-on-dark.png&#34;
	width=&#34;4778&#34;
	height=&#34;2670&#34;
	srcset=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-11-29-diagram-on-dark_hu_e41c3fe0602326f5.png 480w, https://mike42.me/blog/2025-12-farewell-wordpress/2025-11-29-diagram-on-dark_hu_cfb89b29205531d4.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Dark mode&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;178&#34;
		data-flex-basis=&#34;429px&#34;
	
&gt; &lt;img src=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-11-29-diagram-in-gallery.png&#34;
	width=&#34;4778&#34;
	height=&#34;2670&#34;
	srcset=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-11-29-diagram-in-gallery_hu_b8d1bcf44d666bd4.png 480w, https://mike42.me/blog/2025-12-farewell-wordpress/2025-11-29-diagram-in-gallery_hu_4b9e10f474098f58.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Gallery view&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;178&#34;
		data-flex-basis=&#34;429px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m rendering SVG files over a white background as a work-around - SVG files are not supported in the gallery plugin, but even this breaks in Firefox reader mode for example.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-11-29-svg-example.png&#34;
	width=&#34;4778&#34;
	height=&#34;2670&#34;
	srcset=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-11-29-svg-example_hu_22c3d961f7c34b1b.png 480w, https://mike42.me/blog/2025-12-farewell-wordpress/2025-11-29-svg-example_hu_3098284f4bb53b0d.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;An SVG circuit diagram&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;178&#34;
		data-flex-basis=&#34;429px&#34;
	
&gt; &lt;img src=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-11-29-svg-reader-mode.png&#34;
	width=&#34;4778&#34;
	height=&#34;2670&#34;
	srcset=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-11-29-svg-reader-mode_hu_c739115a63f6970b.png 480w, https://mike42.me/blog/2025-12-farewell-wordpress/2025-11-29-svg-reader-mode_hu_7c3b6f93dea76fad.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;In reader view&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;178&#34;
		data-flex-basis=&#34;429px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I plan to test a few possible solutions as I write new pages, and go back and fix posts where time allows.&lt;/p&gt;
&lt;p&gt;Side note: Long ago a reader commented that my schematics were unreadable, and I&amp;rsquo;m only now realising that they could have been using AMP, a feed reader, an email client, or number of other alternative ways to access the blog which could have had this issue.&lt;/p&gt;
&lt;h3 id=&#34;comments&#34;&gt;Comments
&lt;/h3&gt;&lt;p&gt;My blog allowed interactivity in the form of comments, but I made the difficult decision to remove this. I&amp;rsquo;ve saved old comments just in case, but don&amp;rsquo;t plan to re-publish them at this stage.&lt;/p&gt;
&lt;p&gt;Static sites don&amp;rsquo;t directly support comments, but can embed a commenting widget from an external service.&lt;/p&gt;
&lt;p&gt;I checked through a few of the available options, and couldn&amp;rsquo;t find any which made sense for this site when considering the trade-offs between user privacy, cost and moderation burden.&lt;/p&gt;
&lt;h3 id=&#34;subscribers&#34;&gt;Subscribers
&lt;/h3&gt;&lt;p&gt;Another loss from the Wordpress ecosystem was the ability for users to subscribe to new posts, so that they receive a notification when they are published.&lt;/p&gt;
&lt;p&gt;I exported my list of subscribers, so that I can send a one-off email to suggest migration if I ever set up an alternative system for receiving notifications.&lt;/p&gt;
&lt;h3 id=&#34;analytics&#34;&gt;Analytics
&lt;/h3&gt;&lt;p&gt;Wordpress also provided me with basic analytics. I didn&amp;rsquo;t use these extensively, but it was good to know which pages were popular.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-08-wordpress-stats.png&#34;
	width=&#34;3562&#34;
	height=&#34;2060&#34;
	srcset=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-08-wordpress-stats_hu_2a01c93cb5483e71.png 480w, https://mike42.me/blog/2025-12-farewell-wordpress/2025-08-wordpress-stats_hu_c12bc2f71eaf678d.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Wordpress page stats&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;172&#34;
		data-flex-basis=&#34;414px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This is the most likely area where I&amp;rsquo;ll deploy something self-hosted.&lt;/p&gt;
&lt;h3 id=&#34;search&#34;&gt;Search
&lt;/h3&gt;&lt;p&gt;My theme ships with a basic client-side search function. This is good enough, but I have some ideas for how to improve/replace this if I ever have the time to work on it.&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap-up
&lt;/h2&gt;&lt;p&gt;Hugo had a more challenging out-of-the-box experience than I expected, with multiple editions, no reference theme, and a need to fork &amp;amp; edit the theme to achieve any customisation.&lt;/p&gt;
&lt;p&gt;I still think it was the right move for this site, and Hugo&amp;rsquo;s rough edges are worth it for the benefit of having a self-contained tool to build the site. Comparable static site generators seem to all require a working Node, Ruby or Python setup, plus their associated package managers, which is too many moving parts for publishing the occasional blog post.&lt;/p&gt;
&lt;p&gt;I checked Google&amp;rsquo;s pagespeed score on one of my blog posts before and after this change. Even though higher resolution images are now being used, it went up from 79 to 91.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-08-pagespeed-performance.png&#34;
	width=&#34;3562&#34;
	height=&#34;2060&#34;
	srcset=&#34;https://mike42.me/blog/2025-12-farewell-wordpress/2025-08-pagespeed-performance_hu_75569b2fc30f2b8d.png 480w, https://mike42.me/blog/2025-12-farewell-wordpress/2025-08-pagespeed-performance_hu_5abd5c310cdd9da4.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Pagespeed performance after change&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;172&#34;
		data-flex-basis=&#34;414px&#34;
	
&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Switching between VFIO-enabled virtual machines</title>
        <link>https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines</link>
        <pubDate>Thu, 25 Apr 2024 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines</guid>
        <description>&lt;p&gt;For the past few months, I&amp;rsquo;ve been using a setup for software development where I pass the mouse, keyboard and graphics card to a virtual machine via Linux VFIO. The setup is described in detail in &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development&#34; &gt;its own blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In short though, the idea is to provision a separate virtual machine for each project, so that I can install whatever tools I need to solve the problem at hand, with no real consequences if I break my install.&lt;/p&gt;
&lt;h2 id=&#34;the-problem&#34;&gt;The problem
&lt;/h2&gt;&lt;p&gt;I have multiple virtual machines which are configured to use the same hardware, so I can only run one at a time. Before making the changes outlined in this blog post, the method I used to switch to a different VM was unwieldy: I needed to shut down the current VM, switch monitor inputs to the host graphics, start a different VM, then switch monitor inputs back the the VM graphics.&lt;/p&gt;
&lt;p&gt;I intend to do all of my work in VM&amp;rsquo;s, so my basic goal was to make a &amp;lsquo;switch VM&amp;rsquo; mechanism available &lt;em&gt;from within a VM&lt;/em&gt;, to remove any need to interact with the host operating system directly.&lt;/p&gt;
&lt;h2 id=&#34;creating-an-api&#34;&gt;Creating an API
&lt;/h2&gt;&lt;p&gt;My plan for this was to run an agent on the host, which will accept a request to switch VM&amp;rsquo;s. It would then shut down the current VM, and start up a different one instead.&lt;/p&gt;
&lt;p&gt;This was the first time I tried using the libvirt Python bindings before, and I was able to quickly make a script which toggled between two VM&amp;rsquo;s, which are nested within the VM I&amp;rsquo;m using for development, because of course they are.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-vm-switch-demo-reduced.gif&#34;
	width=&#34;885&#34;
	height=&#34;494&#34;
	
	loading=&#34;lazy&#34;
	
		alt=&#34;Toggling which VM is active, using the Python libvirt API in PyCharm.&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;179&#34;
		data-flex-basis=&#34;429px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I then extended this to use an orderly shutdown, and to work with an arbitrary number of VM&amp;rsquo;s. CirrOS was not completing its boot in this environment, so I switched the test VM&amp;rsquo;s to Debian, and also passed through a USB device to each of them so that I would get an error if I ever tried to boot both VM&amp;rsquo;s simultaneously.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-vm-switch-one-at-a-time.png&#34;
	width=&#34;1169&#34;
	height=&#34;712&#34;
	srcset=&#34;https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-vm-switch-one-at-a-time_hu_6f24814e92eed5bc.png 480w, https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-vm-switch-one-at-a-time_hu_943ebe947be3b1a4.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;164&#34;
		data-flex-basis=&#34;394px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Last, I exposed this over HTTP as a simple API.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-vm-switch-over-http.png&#34;
	width=&#34;1745&#34;
	height=&#34;1187&#34;
	srcset=&#34;https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-vm-switch-over-http_hu_88d3be42a0b02b67.png 480w, https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-vm-switch-over-http_hu_8279bc9fe8cf7552.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;147&#34;
		data-flex-basis=&#34;352px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;For the first iteration, I installed this on the host, and placed some scripts in a folder which is shared between all of the VM&amp;rsquo;s. The scripts use &lt;code&gt;curl&lt;/code&gt; commands to call the API. To trigger a VM switch (or a shutdown of the host), I could go to a folder, and run one of these scripts.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-bash-scripts-to-switch-vm.png&#34;
	width=&#34;1537&#34;
	height=&#34;611&#34;
	srcset=&#34;https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-bash-scripts-to-switch-vm_hu_610153db1342ef5d.png 480w, https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-bash-scripts-to-switch-vm_hu_8f6c3da47d15c5da.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;251&#34;
		data-flex-basis=&#34;603px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;web-ui&#34;&gt;Web UI
&lt;/h2&gt;&lt;p&gt;With that proof-of-concept out of the way, I made a web interface, so that I can use this instead of some bash scripts in a folder. This is a very simple Angular app.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-vm-switch-web-ui.png&#34;
	width=&#34;1546&#34;
	height=&#34;916&#34;
	srcset=&#34;https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-vm-switch-web-ui_hu_a63552ddc5b2a4ba.png 480w, https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-vm-switch-web-ui_hu_af1e6762c5ed0077.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;168&#34;
		data-flex-basis=&#34;405px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;gnome-extension&#34;&gt;GNOME extension
&lt;/h2&gt;&lt;p&gt;For the most part, I&amp;rsquo;m working on Debian using the GNOME desktop environment, which gives me some options for integrating this further into my desktop.&lt;/p&gt;
&lt;p&gt;I first considered making a &lt;a class=&#34;link&#34; href=&#34;https://developer.gnome.org/documentation/tutorials/search-provider.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;search provider&lt;/a&gt;, but settled instead for making a simple standalone extension to display an indicator instead, based on the example app shown running here.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-app-indicator-example.png&#34;
	width=&#34;2058&#34;
	height=&#34;884&#34;
	srcset=&#34;https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-app-indicator-example_hu_f855a0adf5194646.png 480w, https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-app-indicator-example_hu_e931fb1c63861b06.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;232&#34;
		data-flex-basis=&#34;558px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;As if nested virtualization was not mind-bending enough, I started testing this using a GNOME session within a GNOME session.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-gnome-plugin-testing.png&#34;
	width=&#34;1800&#34;
	height=&#34;719&#34;
	srcset=&#34;https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-gnome-plugin-testing_hu_6d3c2eebc7e1598c.png 480w, https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-gnome-plugin-testing_hu_95c8a53e9c40d5ab.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;250&#34;
		data-flex-basis=&#34;600px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The extension is written in JavaScript, though the JavaScript API for GNOME extensions was very unfamiliar to me. There some obvious quality issues in the code, but it&amp;rsquo;s not being published to a repository, and it fires off the correct HTTP requests, so I&amp;rsquo;ll call it a success.&lt;/p&gt;
&lt;p&gt;Deploying a GNOME extension manually is as simple as placing some files my home directory.&lt;/p&gt;
&lt;h2 id=&#34;result-and-next-steps&#34;&gt;Result and next steps
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;ve bookmarked the path to my VM switcher web app in each of my VM&amp;rsquo;s.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-vm-switch-web-interface.png&#34;
	width=&#34;1344&#34;
	height=&#34;1168&#34;
	srcset=&#34;https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-vm-switch-web-interface_hu_8b0aa3961e7cd5a5.png 480w, https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-vm-switch-web-interface_hu_661fe60af269fa4c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;115&#34;
		data-flex-basis=&#34;276px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;And I&amp;rsquo;ve also installed the GNOME extension on the VM that runs on boot.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-vm-switch-gnome-extension.png&#34;
	width=&#34;960&#34;
	height=&#34;540&#34;
	srcset=&#34;https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-vm-switch-gnome-extension_hu_cb486734ae508e3c.png 480w, https://mike42.me/blog/2024-04-switching-between-vfio-enabled-virtual-machines/2024-03-vm-switch-gnome-extension_hu_bd32ad00cb16f520.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The idea of this setup is to have one virtual machine per project, so a good next step would be to make it easier to kick off the install process.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve put the code for this project online at &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/vfio-vm-switcher&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/vfio-vm-switcher&lt;/a&gt; on GitHub.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Going all-in on GPU passthrough for software development</title>
        <link>https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development</link>
        <pubDate>Mon, 11 Dec 2023 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development</guid>
        <description>&lt;p&gt;I recently spent some time improving my software development workflow at home, since my previous setup was starting to limit me. I settled on a configuration which uses GPU passthrough with the KVM hypervisor, running Debian as both a host and a guest.&lt;/p&gt;
&lt;p&gt;This post aims to show some of the benefits and drawbacks of this more complex setup for my use case, as well as a specific combination of hardware and software which can be made to work.&lt;/p&gt;
&lt;h2 id=&#34;background-and-previous-setup&#34;&gt;Background and previous setup
&lt;/h2&gt;&lt;p&gt;I was using &lt;a class=&#34;link&#34; href=&#34;https://www.debian.org/devel/testing&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Debian testing&lt;/a&gt; as a host system, and provisioning project-specific virtual machines to work in via &lt;code&gt;virt-manager&lt;/code&gt;. I use two monitors, and typically had an IDE (in the VM) open on one monitor, and a web browser (on the host) open on the other.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup.png&#34;
	width=&#34;3840&#34;
	height=&#34;2160&#34;
	srcset=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup_hu_ec2c2d48d52f9d2f.png 480w, https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup_hu_6283a50fbb96c051.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The setup is simple and effective:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The VMs ran in the QEMU user session - previously blogged about &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2019-08-how-to-use-the-qemu-bridge-helper-on-debian-10&#34; &gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The path &lt;code&gt;/home/mike/workspace&lt;/code&gt; on the host was shared with every VM via a 9p fileshare.&lt;/li&gt;
&lt;li&gt;Each desktop was set to 1920 x 1080 resolution, with auto-resize disabled. I kept the VM&amp;rsquo;s at this lower resolution to get acceptable graphical performance on 4K monitors when I set this up.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This allowed me to keep the host operating system uncluttered, which I value for both maintainability and security. Modern software development involves running a &lt;em&gt;lot&lt;/em&gt; of code, such as dependencies pulled in via a language-specific package manager, random binaries from GitHub, or tools installed via a sketchy &lt;code&gt;curl ... | sudo sh&lt;/code&gt; command. Better to keep that in a VM.&lt;/p&gt;
&lt;p&gt;The main drawbacks are with the interface into the VM.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Due to scaling, I had imperfect image quality. I also had a small but noticeable input lag when working in my IDE.&lt;/li&gt;
&lt;li&gt;Development involving 3D graphics was impractical due to the performance difference. I reported &lt;a class=&#34;link&#34; href=&#34;https://projects.blender.org/blender/blender-addons/issues/104510&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;a trivial bug&lt;/a&gt; in Blender earlier this year but didn&amp;rsquo;t have an environment suitable for more extensive development on that codebase.&lt;/li&gt;
&lt;li&gt;There was an audio delay when testing within the VM. I created a NES demo &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes&#34; &gt;last year&lt;/a&gt; and this delay was less than ideal when it came to adding sound.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I was at one point triple-booting Debian, Ubuntu 22.04 and Windows, so that I could also run some software which wouldn&amp;rsquo;t work well in this setup.&lt;/p&gt;
&lt;h2 id=&#34;hardware&#34;&gt;Hardware
&lt;/h2&gt;&lt;p&gt;GPU passthrough on consumer hardware is highly dependent on motherboard and BIOS support. The most critical components in my setup are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Motherboard: ASUS TUF X470-PLUS GAMING&lt;/li&gt;
&lt;li&gt;CPU: AMD Ryzen 7 5800X&lt;/li&gt;
&lt;li&gt;Monitors: 2 x LG 27UD58&lt;/li&gt;
&lt;li&gt;Graphics card: AMD Radeon RX 6950 XT
&lt;ul&gt;
&lt;li&gt;Installed at &lt;code&gt;PCIEX16_1&lt;/code&gt;, directly connected to the CPU&lt;/li&gt;
&lt;li&gt;Connected to DisplayPort inputs on the two monitors&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I added one component specifically for this setup:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Second graphics card: AMD Radeon RX 6400
&lt;ul&gt;
&lt;li&gt;Installed at &lt;code&gt;PCIEX16_2&lt;/code&gt;, connected to chipset&lt;/li&gt;
&lt;li&gt;Connected to HDMI inputs on the two monitors (one directly, one via an adapter)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The second graphics card will be used by the host. The RX 6400 is a low-cost, low-power, low-profile card which supports UEFI, Vulkan and the modern amdgpu driver.&lt;/p&gt;
&lt;p&gt;In the slot I&amp;rsquo;ve installed it, it&amp;rsquo;s limited to PCIE 2.0 x4, and 1920 x 1080 is the highest resolution I can run at 60 Hz on these monitor inputs. I only need to use this to set up the VM&amp;rsquo;s, or as a recovery interface, so I&amp;rsquo;m not expecting this to be a major issue.&lt;/p&gt;
&lt;h2 id=&#34;inspecting-iommu-groups&#34;&gt;Inspecting IOMMU groups
&lt;/h2&gt;&lt;p&gt;On a fresh install of Debian 12, I started walking through the &lt;a class=&#34;link&#34; href=&#34;https://wiki.archlinux.org/title/PCI_passthrough_via_OVMF&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;PCI passthrough via OVMF&lt;/a&gt; guide on the Arch Wiki, adapting it for my specific setup as necessary.&lt;/p&gt;
&lt;p&gt;I verified that I was using UEFI boot, had SVM and IOMMU enabled, and I also enabled resizable BAR. I did not set any IOMMU-related Linux boot options, and also could not find a firmware setting to select which graphics card to use during boot.&lt;/p&gt;
&lt;p&gt;Using the script on the Arch Wiki, I then printed out the IOMMU groups on my hardware, which are as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 0:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	00:01.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 1:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	00:01.1 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse GPP Bridge [1022:1483]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 2:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	00:01.3 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse GPP Bridge [1022:1483]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 3:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	00:02.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 4:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	00:03.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 5:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	00:03.1 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse GPP Bridge [1022:1483]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 6:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	00:04.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 7:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	00:05.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 8:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	00:07.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 9:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	00:07.1 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Internal PCIe GPP Bridge 0 to bus[E:B] [1022:1484]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 10:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	00:08.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 11:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	00:08.1 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Internal PCIe GPP Bridge 0 to bus[E:B] [1022:1484]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 12:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	00:14.0 SMBus [0c05]: Advanced Micro Devices, Inc. [AMD] FCH SMBus Controller [1022:790b] (rev 61)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	00:14.3 ISA bridge [0601]: Advanced Micro Devices, Inc. [AMD] FCH LPC Bridge [1022:790e] (rev 51)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 13:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	00:18.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Matisse/Vermeer Data Fabric: Device 18h; Function 0 [1022:1440]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	00:18.1 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Matisse/Vermeer Data Fabric: Device 18h; Function 1 [1022:1441]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	00:18.2 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Matisse/Vermeer Data Fabric: Device 18h; Function 2 [1022:1442]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	00:18.3 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Matisse/Vermeer Data Fabric: Device 18h; Function 3 [1022:1443]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	00:18.4 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Matisse/Vermeer Data Fabric: Device 18h; Function 4 [1022:1444]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	00:18.5 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Matisse/Vermeer Data Fabric: Device 18h; Function 5 [1022:1445]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	00:18.6 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Matisse/Vermeer Data Fabric: Device 18h; Function 6 [1022:1446]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	00:18.7 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Matisse/Vermeer Data Fabric: Device 18h; Function 7 [1022:1447]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 14:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	01:00.0 Non-Volatile memory controller [0108]: Samsung Electronics Co Ltd NVMe SSD Controller SM981/PM981/PM983 [144d:a808]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 15:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	02:00.0 USB controller [0c03]: Advanced Micro Devices, Inc. [AMD] Device [1022:43d0] (rev 01)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	02:00.1 SATA controller [0106]: Advanced Micro Devices, Inc. [AMD] 400 Series Chipset SATA Controller [1022:43c8] (rev 01)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	02:00.2 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] 400 Series Chipset PCIe Bridge [1022:43c6] (rev 01)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	03:00.0 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] 400 Series Chipset PCIe Port [1022:43c7] (rev 01)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	03:01.0 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] 400 Series Chipset PCIe Port [1022:43c7] (rev 01)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	03:02.0 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] 400 Series Chipset PCIe Port [1022:43c7] (rev 01)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	03:03.0 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] 400 Series Chipset PCIe Port [1022:43c7] (rev 01)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	03:04.0 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] 400 Series Chipset PCIe Port [1022:43c7] (rev 01)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	03:09.0 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] 400 Series Chipset PCIe Port [1022:43c7] (rev 01)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	04:00.0 Ethernet controller [0200]: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller [10ec:8168] (rev 15)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	08:00.0 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD/ATI] Navi 10 XL Upstream Port of PCI Express Switch [1002:1478] (rev c7)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	09:00.0 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD/ATI] Navi 10 XL Downstream Port of PCI Express Switch [1002:1479]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	0a:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Navi 24 [Radeon RX 6400/6500 XT/6500M] [1002:743f] (rev c7)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	0a:00.1 Audio device [0403]: Advanced Micro Devices, Inc. [AMD/ATI] Navi 21/23 HDMI/DP Audio Controller [1002:ab28]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	0b:00.0 Non-Volatile memory controller [0108]: Sandisk Corp WD Blue SN550 NVMe SSD [15b7:5009] (rev 01)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 16:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	0c:00.0 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD/ATI] Navi 10 XL Upstream Port of PCI Express Switch [1002:1478] (rev c0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 17:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	0d:00.0 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD/ATI] Navi 10 XL Downstream Port of PCI Express Switch [1002:1479]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 18:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	0e:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Navi 21 [Radeon RX 6950 XT] [1002:73a5] (rev c0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 19:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	0e:00.1 Audio device [0403]: Advanced Micro Devices, Inc. [AMD/ATI] Navi 21/23 HDMI/DP Audio Controller [1002:ab28]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 20:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	0f:00.0 Non-Essential Instrumentation [1300]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Function [1022:148a]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 21:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	10:00.0 Non-Essential Instrumentation [1300]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Reserved SPP [1022:1485]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 22:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	10:00.1 Encryption controller [1080]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Cryptographic Coprocessor PSPCPP [1022:1486]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 23:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	10:00.3 USB controller [0c03]: Advanced Micro Devices, Inc. [AMD] Matisse USB 3.0 Host Controller [1022:149c]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOMMU Group 24:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	10:00.4 Audio device [0403]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse HD Audio Controller [1022:1487]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Passthrough for an IOMMU group is all-or nothing. For example, all of the chipset-connected devices are grouped together, and I can&amp;rsquo;t pass any of them through to a VM unless I pass them &lt;em&gt;all&lt;/em&gt; through.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m mainly interested in a graphics card, an audio device, and a USB controller, and helpfully I have one of each isolated in their own groups, presumably because they are connected to PCIe lanes which go directly to the CPU.&lt;/p&gt;
&lt;p&gt;&lt;div class=&#34;img-canvas-outer&#34;&gt;
&lt;a href=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-device-diagram-vertical-1.svg&#34; class=&#34;img-canvas-link  img-md&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-device-diagram-vertical-1.svg&#34;
	
	
	
	loading=&#34;lazy&#34;
	
	
	    class=&#34;img-canvas-inner&#34; 
	
&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;h2 id=&#34;graphics&#34;&gt;Graphics
&lt;/h2&gt;&lt;p&gt;I created a virtual machine, also Debian 12, in the QEMU system session. The only important setting for now is the chipset and firmware, and in my case I selected Q35, and the OVMF UEFI firmware. GPU passthrough will not work if a virtual machine is booting with legacy BIOS.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-16.png&#34;
	width=&#34;1076&#34;
	height=&#34;899&#34;
	srcset=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-16_hu_2a51bbb62c215cf8.png 480w, https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-16_hu_4a6f14b4a13f924d.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;119&#34;
		data-flex-basis=&#34;287px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I use the &lt;a class=&#34;link&#34; href=&#34;https://webglsamples.org/aquarium/aquarium.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;WebGL Aquarium&lt;/a&gt; as a simple test for whether 3D acceleration is working. It runs much faster on the host system (this is using the RX 6400). The copy in the VM runs at just 3 frames per second, using SPICE display and &lt;code&gt;virtio&lt;/code&gt; virtual GPU at this stage.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-07.png&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-07_hu_201681cc10df1412.png 480w, https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-07_hu_63ec8a6889726be6.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The next step was to isolate the GPU from the host. The relevant line from &lt;code&gt;lspci -nn&lt;/code&gt; is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0e:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Navi 21 [Radeon RX 6950 XT] [1002:73a5] (rev c0)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The vendor and device ID for this card is shown at the end of the line, &lt;code&gt;1002:73a5&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This needs to be added to the &lt;code&gt;vfio-pci.ids&lt;/code&gt; boot option, which in my case involves updating &lt;code&gt;/etc/default/grub&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;GRUB_CMDLINE_LINUX=&amp;#34;vfio-pci.ids=1002:73a5&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is then applied by running &lt;code&gt;update-grub2&lt;/code&gt;, and rebooting. It&amp;rsquo;s apparently possible to accomplish this without a reboot, but I&amp;rsquo;m following the easy path for now.&lt;/p&gt;
&lt;p&gt;I verified that it worked by checking that the &lt;code&gt;vfio-pci&lt;/code&gt; kernel module is in use for this device.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ lspci -v
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0e:00.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Navi 21 [Radeon RX 6950 XT] (rev c0) (prog-if 00 [VGA controller])
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        Kernel driver in use: vfio-pci
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        Kernel modules: amdgpu
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Before booting up the VM, I added the card as a &amp;ldquo;Host PCI Device&amp;rdquo;. It was then visible in &lt;code&gt;lspci&lt;/code&gt; output within the VM, but was not being used for video output yet.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-09.png&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-09_hu_c773c3e74814a27f.png 480w, https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-09_hu_583bd2b28a29edf4.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;To encourage the VM to output to the physical graphics card, I switched the virtualised video card model from &amp;ldquo;virtio&amp;rdquo; to &amp;ldquo;None&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-02.png&#34;
	width=&#34;1431&#34;
	height=&#34;835&#34;
	srcset=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-02_hu_596f206052cb7f10.png 480w, https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-02_hu_b3382ba89f673a09.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;171&#34;
		data-flex-basis=&#34;411px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Booting up the VM after this change, the SPICE display no longer produces output, but USB redirection still works. I passed through the keyboard, then the mouse.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-10.png&#34;
	width=&#34;416&#34;
	height=&#34;264&#34;
	srcset=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-10_hu_e8761369b8d9a37b.png 480w, https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-10_hu_5ddff075f60adad8.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;157&#34;
		data-flex-basis=&#34;378px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I then switched monitor inputs to the VM, now equipped with a graphics card, and the WebGL aquarium test ran at 30 FPS.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-03.png&#34;
	width=&#34;3840&#34;
	height=&#34;2160&#34;
	srcset=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-03_hu_4e57b62fe77f622b.png 480w, https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-03_hu_3c0a113718b5f576.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Now that I was switching between near-identical Debian systems, I started using different desktop backgrounds to stay oriented.&lt;/p&gt;
&lt;h2 id=&#34;audio-output&#34;&gt;Audio output
&lt;/h2&gt;&lt;p&gt;I needed to make sure that audio output worked reliably in the virtual machine.&lt;/p&gt;
&lt;p&gt;Sound was working out of the box through the emulated AC97 device, but I checked an online &lt;a class=&#34;link&#34; href=&#34;https://www.youtube.com/watch?v=ucZl6vQ_8Uo&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Audio Video Sync Test&lt;/a&gt;, and confirmed that there was a significant delay, somewhere in in the 200-300ms range. This is not good enough, so I deleted the emulated device and decided to try some other options.&lt;/p&gt;
&lt;p&gt;I first tried passing through the audio device associated with the graphics card, identified as &lt;code&gt;1002:ab28&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0e:00.1 Audio device [0403]: Advanced Micro Devices, Inc. [AMD/ATI] Navi 21/23 HDMI/DP Audio Controller [1002:ab28]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I took the ID, and added it to the option in &lt;code&gt;/etc/default/grub&lt;/code&gt;. Now that there are multiple devices, they are separated by commas.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;GRUB_CMDLINE_LINUX=&amp;#34;vfio-pci.ids=1002:73a5,1002:ab28&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As before, I ran &lt;code&gt;update-grub2&lt;/code&gt;, rebooted, added the device to the VM through &lt;code&gt;virt-manager&lt;/code&gt;, booted up the VM, and tried to use the device.&lt;/p&gt;
&lt;p&gt;With that change, I could connect headphones to the monitor and the audio was no longer delayed. This environment would now be viable for developing apps with sound, or following along with a video tutorial for example.&lt;/p&gt;
&lt;h2 id=&#34;audio-input&#34;&gt;Audio input
&lt;/h2&gt;&lt;p&gt;Next I attempted to pass through the on-board audio controller to see if I could get both audio input and output. Discussions online suggest that this doesn&amp;rsquo;t always work, but there is no harm in trying.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll skip through the exact process this time, but I again identified the device, isolated it from the host, and passed it through to a VM.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;10:00.4 Audio device [0403]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse HD Audio Controller [1022:1487]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Output worked immediately, but the settings app did not show any microphone level, and attempts to capture would immediately stop. I did some basic reading and troubleshooting, but didn&amp;rsquo;t have a good idea of what was happening.&lt;/p&gt;
&lt;p&gt;What worked for me was blindly upgrading my way out of the problem by switching to the Debian testing rolling release in the guest VM.&lt;/p&gt;
&lt;p&gt;I was then able to see the input level in settings, and capture the audio with Audacity.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-12.png&#34;
	width=&#34;3427&#34;
	height=&#34;1817&#34;
	srcset=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-12_hu_eeb5dad16baa74ca.png 480w, https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-12_hu_f89c4741752f57a1.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;188&#34;
		data-flex-basis=&#34;452px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Audio input is not critical for me, but does allow me to move more types of work into virtual machines without switching to a USB sound card.&lt;/p&gt;
&lt;h2 id=&#34;usb&#34;&gt;USB
&lt;/h2&gt;&lt;p&gt;My computer has two USB controllers. One is available for passthrough, while the other is in the same IOMMU group as all other chipset-attached devices.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;02:00.0 USB controller [0c03]: Advanced Micro Devices, Inc. [AMD] Device [1022:43d0] (rev 01)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;10:00.3 USB controller [0c03]: Advanced Micro Devices, Inc. [AMD] Matisse USB 3.0 Host Controller [1022:149c]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The controller I passed through is the &amp;ldquo;Matisse USB 3.0 Host Controller&amp;rdquo;, device ID &lt;code&gt;1022:149c&lt;/code&gt;, which I initially expected would have plenty of USB 3 ports attached to it.&lt;/p&gt;
&lt;p&gt;Reading the manual for my motherboard more carefully, I discovered that this controller is only responsible for 2 USB-A ports and 1 USB-C port, or 20% of the USB ports on the system.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-13.png&#34;
	width=&#34;505&#34;
	height=&#34;172&#34;
	srcset=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-13_hu_c484b40e45cbeeb7.png 480w, https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-13_hu_a1418e0df1c9106f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;293&#34;
		data-flex-basis=&#34;704px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I use a lot of USB peripherals for &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/tag/hardware&#34; &gt;hardware development&lt;/a&gt;. More physical USB ports would be ideal, but I can work around this by using a USB hub.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll also continue to use USB passthrough via libvirt to get the keyboard and mouse into the VM. Instead of manually passing these through each time I start the VM, I added each device in the configuration as a &amp;ldquo;Physical USB Device&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-15.png&#34;
	width=&#34;1000&#34;
	height=&#34;765&#34;
	srcset=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-15_hu_d011cb8ba8c50826.png 480w, https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-15_hu_c83617e3a35e1da5.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;130&#34;
		data-flex-basis=&#34;313px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This automatically connects the device when the VM boots, and returns it to the host when the VM shuts down, without the SPICE console needing to be open. If I need to control the host and guest at the same time, I can connect a different mouse and keyboard temporarily - I&amp;rsquo;ve got plenty of USB ports on the host after all.&lt;/p&gt;
&lt;p&gt;If this ever becomes a major issue, it should also be possible to switch this setup around, and pass through the IOMMU group containing all chipset-attached PCIe devices instead of the devices I&amp;rsquo;ve chosen. This would provide extensive I/O and expansion options to the VM, at the cost of things like on-board networking, SATA ports, and an NVMe slot on the host. The 3 USB ports on the &amp;ldquo;Matisse USB 3.0 Host Controller&amp;rdquo;, if left to the host, would be just enough for a mouse, keyboard, and USB-C Ethernet adapter.&lt;/p&gt;
&lt;h2 id=&#34;file-share&#34;&gt;File share
&lt;/h2&gt;&lt;p&gt;On my previous setup, I used a 9p fileshare to map a directory on the host to the same path on every VM, allowing an easy way to exchange files.&lt;/p&gt;
&lt;p&gt;The path was &lt;code&gt;/home/mike/workspace&lt;/code&gt; - a carry-over from when I used &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Eclipse_%28software%29&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Eclipse&lt;/a&gt;. In practice it has been slower to work on a fileshare, so I&amp;rsquo;ll switch to developing in a local directory.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll still set up a fileshare, but with two changes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I&amp;rsquo;ll map a share to a more generic &lt;code&gt;/home/mike/Shared&lt;/code&gt;, and start to &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas&#34; &gt;back up&lt;/a&gt; anything that lands there.&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;ll use virtiofs instead of virtio-9p. This claims to be more performant, and it&amp;rsquo;s &lt;a class=&#34;link&#34; href=&#34;https://virtio-fs.gitlab.io/howto-windows.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;apparently possible&lt;/a&gt; to get this working on Windows as well.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is added as a hardware device in virt-manager on the host.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-08.png&#34;
	width=&#34;1000&#34;
	height=&#34;765&#34;
	srcset=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-08_hu_6ee3a59258455c99.png 480w, https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-08_hu_bcf88fa0e1154acd.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;130&#34;
		data-flex-basis=&#34;313px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;In the guest, I added the following line to &lt;code&gt;/etc/fstab&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;shared /home/mike/Shared/ virtiofs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To activate this change, I would previously have created the mount-point and run &lt;code&gt;mount -a&lt;/code&gt;. I recently learned that systemd creates mount-points automatically on modern systems, so I instead ran the &lt;a class=&#34;link&#34; href=&#34;https://bbs.archlinux.org/viewtopic.php?id=192991&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;correct incantation&lt;/a&gt; to trigger this process, which is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sudo&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;systemctl&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;daemon&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;reload&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sudo&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;systemctl&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;restart&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;power-management&#34;&gt;Power management
&lt;/h2&gt;&lt;p&gt;In my current setup, sleep/wake causes instability. I initially disabled idle suspend on the host in GNOME:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-05.png&#34;
	width=&#34;409&#34;
	height=&#34;289&#34;
	srcset=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-05_hu_586c076e4382a510.png 480w, https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-05_hu_f4c43600ec236314.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;141&#34;
		data-flex-basis=&#34;339px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;While testing a VM which I had configured to start on boot, the system decided to go to sleep while I was using it. In hindsight this makes complete sense: as far as the host could tell, it was sitting on the login page with no mouse or keyboard input, and had been configured to go to sleep after an idle time-out (the setting within GNOME only applies after login).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Dec 05 16:24:43 mike-kvm systemd-logind[706]: The system will suspend now!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To avoid this, I additionally disabled relevant systemd units (&lt;a class=&#34;link&#34; href=&#34;https://www.tecmint.com/disable-suspend-and-hibernation-in-linux/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;source of this command&lt;/a&gt;).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Created symlink /etc/systemd/system/sleep.target → /dev/null.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Created symlink /etc/systemd/system/suspend.target → /dev/null.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Created symlink /etc/systemd/system/hibernate.target → /dev/null.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Created symlink /etc/systemd/system/hybrid-sleep.target → /dev/null.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ve also configured each VM to simply blank the screen when idle, since allowing a guest to suspend causes its own problems.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-17.png&#34;
	width=&#34;641&#34;
	height=&#34;609&#34;
	srcset=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-17_hu_468ae8cd3522ea75.png 480w, https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-17_hu_e86efcbf2654c20a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;105&#34;
		data-flex-basis=&#34;252px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;recap-of-unexpected-issues&#34;&gt;Recap of unexpected issues
&lt;/h2&gt;&lt;p&gt;Despite my efforts to plan around the limitations of my hardware, I did hit four unanticipated problems, mostly highlighted above.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I assumed that there would be a setting in my BIOS to change which graphics card to use during boot, but I couldn&amp;rsquo;t find one.&lt;/li&gt;
&lt;li&gt;The audio devices associated with both of my graphics cards had the same vendor and device ID. The way I have it configured, no audio output is available on the host as a result.&lt;/li&gt;
&lt;li&gt;Microphone input didn&amp;rsquo;t work on the HD Audio Controller until I upgraded the guest operating system. The usual workaround for this is apparently to use a USB sound card.&lt;/li&gt;
&lt;li&gt;I misunderstood the limitations of my USB setup, so I have fewer USB ports directly available in the VM than I had hoped for.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;wrap-up-and-future-ideas&#34;&gt;Wrap-up and future ideas
&lt;/h2&gt;&lt;p&gt;I really like the idea of switching into an environment which only has the tools I need for the task at hand. Compared with my previous setup for developing in a VM, GPU passthrough (and sound controller passthrough, and USB controller passthrough) is a huge improvement.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve manually provisioned 3 VM&amp;rsquo;s, including a general-purpose development VM which has a mix of basic tools so that I can get started.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-11.png&#34;
	width=&#34;3840&#34;
	height=&#34;2160&#34;
	srcset=&#34;https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-11_hu_b677b653a305781a.png 480w, https://mike42.me/blog/2023-12-going-all-in-on-gpu-passthrough-for-software-development/2023-12-development-setup-11_hu_1aa77370f6a61e15.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Since I can only have one VM using the graphics card at a time, this setup works similarly to having multiple operating systems installed as a multi-boot setup. It does however have far better separation between the systems - they can&amp;rsquo;t read and write each others&amp;rsquo; disks for example.&lt;/p&gt;
&lt;p&gt;The next steps for me will be to streamline the process of switching VM&amp;rsquo;s and shutting down the system. Both of these currently require me to manually switch monitor inputs to interact with the host, which I would prefer to avoid.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Building a 1U quiet NAS</title>
        <link>https://mike42.me/blog/2023-10-building-a-1u-quiet-nas</link>
        <pubDate>Sun, 22 Oct 2023 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2023-10-building-a-1u-quiet-nas</guid>
        <description>&lt;p&gt;I recently built a compact, quiet rackmount NAS for home. I haven&amp;rsquo;t seen any builds quite like it online, so I&amp;rsquo;m writing a bit about how it came together.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-build.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-build_hu_201eb308ac80c053.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-build_hu_e526e617e1410431.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;the-problem&#34;&gt;The problem
&lt;/h2&gt;&lt;p&gt;My old backup was a &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2017-12-how-to-assemble-linux-software-raid-on-a-new-computer&#34; &gt;mirrored pair of 2 TB hard drives&lt;/a&gt; in an old desktop computer, with a portable 2 TB hard drive as an off-site copy. The disks are now 9 years old, and 2 TB is small enough that I need to ration the space. I also recently repurposed most of the components in that system, so I no longer have an up-to-date backup.&lt;/p&gt;
&lt;p&gt;I want to solve this properly, and hopefully build a replacement setup which I can install in my network cabinet, to run 24/7.&lt;/p&gt;
&lt;p&gt;But if I&amp;rsquo;m going to do that, the must-haves are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It fits in a 1U rack-mount form-factor with maximum 25cm depth&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s quiet&lt;/li&gt;
&lt;li&gt;It has front USB for making an offline copy of the backups&lt;/li&gt;
&lt;li&gt;It has 2 SATA disks - I don&amp;rsquo;t want to be running a NAS off USB-SATA adapters, for example&lt;/li&gt;
&lt;li&gt;It has wired ethernet - my network is 1 Gigabit&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nice-to-haves would be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fast front USB&lt;/li&gt;
&lt;li&gt;Hot-swap disks or more disks&lt;/li&gt;
&lt;li&gt;Faster network&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;ve worked with servers, and I&amp;rsquo;ve &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc&#34; &gt;built&lt;/a&gt; small-form-factor computers, so how hard can it be to build a small-form-factor server?&lt;/p&gt;
&lt;h2 id=&#34;parts-list&#34;&gt;Parts list
&lt;/h2&gt;&lt;p&gt;I spent a lot of time sketching out possible builds in LibreOffice Draw. Every combination of parts had some compromise, which is a familiar theme from small-form-factor PC building.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-planning-top-view.png&#34;
	width=&#34;2650&#34;
	height=&#34;1606&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-planning-top-view_hu_ce4e4f08622f05a1.png 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-planning-top-view_hu_4b539d64546356a3.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;165&#34;
		data-flex-basis=&#34;396px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I ended up deciding on parts which follow normal PC standards, hopefully giving me a good chance of keeping it working for many years.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Case: Case Athena Power RM1UC138&lt;/li&gt;
&lt;li&gt;Power supply: HDPLEX GAN 250W&lt;/li&gt;
&lt;li&gt;Motherboard: Topton N6005 Mini ITX&lt;/li&gt;
&lt;li&gt;RAM: Crucial 16GB (2 x 8GB) DDR4 3200 SO-DIMM&lt;/li&gt;
&lt;li&gt;Boot disk: Samsung 970 EVO Plus 1TB M.2 SSD&lt;/li&gt;
&lt;li&gt;Storage disks: 2 x Samsung 870 QVO 8TiB 2.5&amp;quot; SSD&lt;/li&gt;
&lt;li&gt;Fans: 4 x Noctua A4x20 PWM&lt;/li&gt;
&lt;li&gt;Drive cage: Icy Dock MB608SP-B - 6 x 2.5&amp;quot; SATA bays&lt;/li&gt;
&lt;li&gt;Set of 6 x 50cm SATA cables&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are some compatibility issues in the above part list, and it took a little bit of problem-solving to get everything working together.&lt;/p&gt;
&lt;h2 id=&#34;closer-look-at-the-athena-power-rm1uc138&#34;&gt;Closer look at the Athena Power RM1UC138
&lt;/h2&gt;&lt;p&gt;Short-depth 1U computer cases are nearly impossible to find in Australia. I ordered the Athena Power RM1UC138 from the United States, which is an OEM case with some flexibility built in.&lt;/p&gt;
&lt;p&gt;On the front it has a 5.25&amp;quot; bay, which I plan to use to add a drive cage. The front USB is only USB 2.0, which would normally be a disadvantage, but in this instance is a good match for the motherboard I&amp;rsquo;m using. The power button looks like a toggle switch, but is actually a momentary switch.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-athena-power-rmuc138-front.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-athena-power-rmuc138-front_hu_c65843e3a8c1f9af.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-athena-power-rmuc138-front_hu_7b96197a926396c1.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The side shows that the rack ears can be put on the front or back, allowing the case to be mounted in either direction.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-athena-power-rmuc138-side.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-athena-power-rmuc138-side_hu_670c5408253dddf9.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-athena-power-rmuc138-side_hu_6adfd462a0cecdf3.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;On the back there is a wire mesh panel for cutting out a custom I/O shield, which is handy since I have an off-brand motherboard.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-athena-power-rmuc138-back.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-athena-power-rmuc138-back_hu_e4e64e85426a9d6d.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-athena-power-rmuc138-back_hu_a432c98c720d2b18.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;On the inside, it&amp;rsquo;s configured for 2 x 3.5&amp;quot; hard drives by default. It also includes 2 x 2-pin 12v fans. They are loud like you would find in most managed network switches, but are not jet-engine loud like most servers. The fan controller simply distributes 12v, and has no speed control.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-athena-power-rmuc138-top.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-athena-power-rmuc138-top_hu_f0d3221b7839f5fe.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-athena-power-rmuc138-top_hu_7fc85feeae67ed84.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This is not a very common case, and I read everything I could find online about it. In order to help the next person who is searching for it, here are two more random pieces of information which I could not confirm until I had the case in-hand:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stand-offs on the case are all 4mm tall and non-removable&lt;/li&gt;
&lt;li&gt;Screw spacing of USB 2.0 front panel connector is approx 30.5mm (from centre of each screw). Stacked USB 3 headers that are 30mm spacing are available online and could be made to work.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;closer-look-at-the-topton-n6005-mini-itx&#34;&gt;Closer look at the Topton N6005 Mini ITX
&lt;/h2&gt;&lt;p&gt;I chose to use a Topton motherboard with a built-in Intel N6005 CPU for this build, since the alternatives were either too tall, use a socketed CPU, use an old CPU, would require add-in cards to get multiple SATA ports, or were not sold in Australia. All of these would make it far more difficult to complete the small, quiet build which I was aiming for.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-topton-n6005-test.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-topton-n6005-test_hu_2d912c6497be8309.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-topton-n6005-test_hu_c7b5aca3e6ba69f1.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;From the few threads online about this board, I gathered that it is fussy about RAM compatibility, so I booted it up at the first opportunity with an SSD containing Pop!_OS to check that it worked. It&amp;rsquo;s not my use case, but this motherboard would definitely be viable as a lightweight desktop.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-topton-n6005-pop-os.png&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-topton-n6005-pop-os_hu_6c8e344812044d53.png 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-topton-n6005-pop-os_hu_c1ce03f75e54576f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The specific memory I used was a 16 GB kit with the model number CT2K8G4SFRA32A. According to Intel&amp;rsquo;s &lt;a class=&#34;link&#34; href=&#34;https://www.intel.com/content/www/us/en/products/sku/212327/intel-pentium-silver-n6005-processor-4m-cache-up-to-3-30-ghz/specifications.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;product documentation&lt;/a&gt;, the N6005 only supports 16 GB maximum, and while I could find claims that higher-capacity memory does work, I couldn&amp;rsquo;t find anybody who posted actual part numbers.&lt;/p&gt;
&lt;p&gt;I was happy to find that the built-in cooler is inaudible at idle loads. This was a bit of a risk: the cooler doesn&amp;rsquo;t have standard dimensions, so I couldn&amp;rsquo;t have easily replaced it with an alternative if it was noisy. Based on other people&amp;rsquo;s experiences with this board, I re-pasted the cooler with Noctua NT-H1 thermal paste, to hopefully help keep temperatures down at higher loads so that the fan will not need to spin up as much. I also avoided using the M.2 slot which receives the most hot air from the cooler.&lt;/p&gt;
&lt;p&gt;Topton also sells an N5105 variant which appears to be more popular (&lt;a class=&#34;link&#34; href=&#34;https://blog.patshead.com/2023/03/i-am-excited-about-the-topton-n5105-mini-itx-nas-motherboard.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;more info here&lt;/a&gt;), as well as an alternative layout which has a PCIe slot instead of a second M.2 slot.&lt;/p&gt;
&lt;h2 id=&#34;custom-power-supply-adapter-plate&#34;&gt;Custom power supply adapter plate
&lt;/h2&gt;&lt;p&gt;The case is designed for a Flex ATX power supply, which is not what I&amp;rsquo;m using. I&amp;rsquo;ve instead opted to use a passively-cooled HDPLEX GAN 250W power supply, which ships with both an IEC C6 and IEC C14 cable.&lt;/p&gt;
&lt;p&gt;I needed to choose one of these cables, and figure out how to securely mount it to the case.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-03-part-psu-problem.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-03-part-psu-problem_hu_8399c8d39eb52b9f.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-03-part-psu-problem_hu_7b2cdb99cb5a2eac.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I designed an adapter plate in FreeCAD around the included IEC C6 cable, since it had threaded holes, and screws were included.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-freecad-design.png&#34;
	width=&#34;3036&#34;
	height=&#34;1766&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-freecad-design_hu_e366fa1fc95be981.png 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-freecad-design_hu_f7c50900b8384424.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;171&#34;
		data-flex-basis=&#34;412px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I ordered it from a prototype supplier in laser cut 1mm steel, painted in matte black.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-freecad-object.png&#34;
	width=&#34;3036&#34;
	height=&#34;1766&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-freecad-object_hu_4382a0d4b87a6d62.png 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-freecad-object_hu_61a6bee140b4678e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;171&#34;
		data-flex-basis=&#34;412px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This is the first time I&amp;rsquo;ve used FreeCAD to design a part, and parametric CAD certainly has a learning curve. For this build, it was well worth it, since the result is better (and safer) than anything I could have improvised.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-03-part-result.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-03-part-result_hu_28d0f875cdcb2154.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-03-part-result_hu_1a945173f4771e5b.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;At the time of writing this post, HDPLEX sells plates for mounting their IEC C14 cables in cases accepting SFX and ATX power supplies, but none for cases which accept Flex ATX power supplies.&lt;/p&gt;
&lt;h2 id=&#34;custom-fan-controller&#34;&gt;Custom fan controller
&lt;/h2&gt;&lt;p&gt;Cooling this build quietly was always going to be a challenge. The case shipped with 2 x 12 V fans, and had a simple splitter which ran them at max speed, which was just too loud.&lt;/p&gt;
&lt;p&gt;I designed a replacement fan controller in KiCad, which allows me to upgrade to high-quality 4-pin fans with PWM speed control, and to set the speed using a potentiometer. I wrote about prototyping this in &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller&#34; &gt;a separate blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-kicad-fan-controller.png&#34;
	width=&#34;3428&#34;
	height=&#34;1798&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-kicad-fan-controller_hu_992a585620e4b373.png 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-kicad-fan-controller_hu_42cace131118b318.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;190&#34;
		data-flex-basis=&#34;457px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This photo shows the custom controller alongside the original one it replaces.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-fan-controller.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-fan-controller_hu_12ce0eece538cc6.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-fan-controller_hu_7a3096741d165331.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;As you can probably guess, I&amp;rsquo;ve designed this to use the same mounting location, at the front of the case. My power supply has no Molex connectors, so I&amp;rsquo;m using a SATA-Molex power adapter.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-fan-controller-in-case.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-fan-controller-in-case_hu_9b1eae36ff32ccc2.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-fan-controller-in-case_hu_c80f7b50e74b7169.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The main drawback to this simple design is that once I close up the case, I can no longer adjust the fan speed.&lt;/p&gt;
&lt;h2 id=&#34;final-assembly&#34;&gt;Final assembly
&lt;/h2&gt;&lt;p&gt;Before continuing any further, I took apart the case completely and deleted three standoffs with a belt sander, to leave a flat area for power supply installation later.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-case-removed-standoffs.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-case-removed-standoffs_hu_8795be964cf379bf.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-case-removed-standoffs_hu_f0b881abac0009bb.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Once I got the case back together, the motherboard went in first. I raised it by 1mm using plastic washers, hoping to line it up better with the I/O shield included with the motherboard.&lt;/p&gt;
&lt;p&gt;The I/O opening for 1U servers is narrower than standard PC builds, so I needed to cut the I/O shield, which I unfortunately did not do correctly.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-assembly-io-shield-01.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-assembly-io-shield-01_hu_ad5347960980df58.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-assembly-io-shield-01_hu_d2d7b9011efd5259.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Since that did not work, I carefully marked and cut out the wire mesh I/O shield included with the case instead. I still left the motherboard raised up on 1mm washers, though this is not necessary anymore. You need to use slightly longer screws if you try this.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-assembly-io-shield-02.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-assembly-io-shield-02_hu_78725dbd53e27564.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-assembly-io-shield-02_hu_80f1ec1d7b1b8b0b.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;After that I installed the four case fans, plus the fan controller. I&amp;rsquo;m using a front-to-back airflow, with 2 x 40mm fans mounted at the front, and 2 x 40mm fans at the back. I added a Y splitter to the back fans, which did not have long enough cables to reach the fan controller.&lt;/p&gt;
&lt;p&gt;The next component I installed was the drive cage. It&amp;rsquo;s worth mentioning at this point that the drive cage also has a fan header, which is the same as a 3-pin header that you would find on a PC motherboard. It supplies a different voltage for each of the speed settings. Medium is approximately 7.5 volts and is relatively quiet with the included &amp;ldquo;Good quality DC fan&amp;rdquo; fan, and high speed is 12 volts. I set mine to off but left the fan installed.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-assembly-drive-cage-01.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-assembly-drive-cage-01_hu_2a4f1e850d36ffab.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-assembly-drive-cage-01_hu_8ec79b2c3129c820.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;To install items into the 5.25&amp;quot; bay in this case, you attach a bracket, then fasten it from above. The bracket allows the depth to be adjusted as well.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-assembly-drive-cage-02.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-assembly-drive-cage-02_hu_d3df0365ff8d9f57.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-assembly-drive-cage-02_hu_c25db28544023438.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I also installed disks in the drive cage at this point, and numbers on the front. Disk 1 is connected to SATA0 on the motherboard, disk 2 is connected to SATA1, and so on.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-assembly-drive-cage-03.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-assembly-drive-cage-03_hu_26fc86545046cae8.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-assembly-drive-cage-03_hu_27dcdbe2617df94a.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Next was the power supply. I installed the custom plate for the power connector, and also installed the mounting plate on the bottom of the PSU so that it would have a flat surface. After confirming that it would fit, I cleaned both surfaces with alcohol, and applied double-sided tape.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-psu-install-01.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-psu-install-01_hu_48fa3465dd7f1d.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-psu-install-01_hu_480e2ba0919a9360.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I then followed a rehearsed path to drop the PSU into place. There is no opportunity to adjust it once it sticks.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-psu-install-02.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-psu-install-02_hu_6bca8b5eaf7ec7bb.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-psu-install-02_hu_ec90b2fde98e46db.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;At this point I connected everything up and booted up the system to start checking for problems, since it&amp;rsquo;s easier to troubleshoot in this state. Two modifications I made here were to disconnect the bright red HDD LED, and to introduce a SATA power Y splitter, because the power supply SATA cables were stretched to the limit.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-assembly-cable-management-required.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-assembly-cable-management-required_hu_3f52877f8d603f39.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-assembly-cable-management-required_hu_2d72386eff8cd74d.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;It took a lot of work (and cable ties) to arrange the cables flat so that the case could close. In defence of cable ties, they do make maintenance more difficult, but that&amp;rsquo;s a worthwhile trade-off for keeping cables clear of airflow paths, fan blades, and the guillotine-like action of the top cover sliding shut.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-assembly-cable-management-done.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-assembly-cable-management-done_hu_e5c66035b0b59da6.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-assembly-cable-management-done_hu_18093c6e3281c6ca.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;completed-build&#34;&gt;Completed build
&lt;/h2&gt;&lt;p&gt;After closing the case, the build is, 434mm × 254mm x 44mm, or 4.8 litres, excluding rack ears.&lt;/p&gt;
&lt;p&gt;This is how it appears from the front.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-front-01.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-front-01_hu_9b702a5e54aa042d.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-front-01_hu_4e5421c1eeb87740.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-front-02.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-front-02_hu_8a05e65c2d2c9152.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-front-02_hu_16c7d4fd2a61f54e.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-front-03.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-front-03_hu_cd0f6b5d7b722488.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-front-03_hu_e33243eeba834308.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-front-04.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-front-04_hu_3db875117b411099.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-front-04_hu_146a2a3efd836f6a.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;And this is how it appears from the back.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-back-01.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-back-01_hu_e8a62ff04a442c45.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-back-01_hu_a2428cd0bd13ec3e.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-back-02.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-back-02_hu_2aa552bc85ee5c9d.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-back-02_hu_9cb0e39cc2cdcac.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-back-03.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-back-03_hu_97c80a417ef82cf1.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-back-03_hu_d9e90fcbce36223d.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-back-04.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-back-04_hu_5a7730d5f37b4247.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-completed-nas-build-back-04_hu_6b2de53ac06f9c41.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;software&#34;&gt;Software
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;m starting with Proxmox, with OpenMediaVault deployed as a virtual machine. I haven&amp;rsquo;t used either of these before, but both are Debian-based and provide convenient web front-ends to the tools I would otherwise be configuring on the command-line.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m &lt;a class=&#34;link&#34; href=&#34;https://pve.proxmox.com/wiki/Passthrough_Physical_Disk_to_Virtual_Machine_%28VM%29&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;passing through the disks as block devices&lt;/a&gt;. Running the NAS like this should make it possible to provision extra workloads which need their own SATA disks in future, or to switch from OpenMediaVault to stock Debian if necessary, all without connecting a monitor.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-omv-install.png&#34;
	width=&#34;2840&#34;
	height=&#34;1402&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-omv-install_hu_d0eeb093a5b7db66.png 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-omv-install_hu_1776d5418c926529.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;202&#34;
		data-flex-basis=&#34;486px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Within OpenMediaVault, I&amp;rsquo;ve configured Linux software RAID, with an ext4 filesystem, shared via Samba, and can access that file share over the network.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-file-share.png&#34;
	width=&#34;2878&#34;
	height=&#34;786&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-file-share_hu_f0ca679cfc401a33.png 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-file-share_hu_aba8207be942831d.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;366&#34;
		data-flex-basis=&#34;878px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve enabled some basic power management features such as C-states. The system idles in the range of 12-14 watts measured from the wall, and goes up to 20 watts when moving files around.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t need a lot of disk capacity, so I&amp;rsquo;ve been able to preserve a useful property of my old setup, where every disk in the system has a full copy of the data, in a format which can be understood by a normal Linux system. This it makes single-disk recovery possible using any surviving disk from the system on practically any computer, and that disk can be from either an offline copy or one of the disks in the RAID mirror.&lt;/p&gt;
&lt;p&gt;I haven&amp;rsquo;t tested the process of making an offline copy of the backup volume, but that will be up next.&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap-up
&lt;/h2&gt;&lt;p&gt;This is possibly the most effort I&amp;rsquo;ve ever put into a PC build. The only unexpected issue I encountered is how heavy it is, and wont be rack-mounting it until I get some generic rails.&lt;/p&gt;
&lt;p&gt;The computer uses a strange mix of parts, but meets my requirements well. I hope that by writing this up, I&amp;rsquo;ll be providing some useful notes to anybody attempting to build something similar.&lt;/p&gt;
&lt;p&gt;This project also gave me a chance to practice my entry-level CAD skills to build something which I&amp;rsquo;ll actually be using. I find a lot of utility in paper prototyping, and printed each design in 1:1 scale to check the physical dimensions before ordering anything.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-prototype-paper-component-01.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-prototype-paper-component-01_hu_71d670163e708b33.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-prototype-paper-component-01_hu_8313e4c7a520f7e.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;For the circuit board, I used a print-out to check each part footprint, as well as the hole locations for fitting it in the case.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-prototype-paper-pcb-01.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-prototype-paper-pcb-01_hu_68647446311194f4.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-prototype-paper-pcb-01_hu_6e3aab4af2276dee.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-prototype-paper-pcb-02.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-prototype-paper-pcb-02_hu_ddd066f85fe9e177.jpg 480w, https://mike42.me/blog/2023-10-building-a-1u-quiet-nas/2023-10-prototype-paper-pcb-02_hu_8f077ea0ae3bcd1c.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;As with many of the projects which I blog about, I&amp;rsquo;ve put the design files up on GitHub. The fan controller is at &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/fan-controller-athena-power&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/fan-controller-athena-power&lt;/a&gt;, while the Flex ATX adapter plate is at &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/flexatx-adapter-hdplex&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/flexatx-adapter-hdplex&lt;/a&gt;.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Controlling computer fans with a microcontroller</title>
        <link>https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller</link>
        <pubDate>Thu, 21 Sep 2023 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller</guid>
        <description>&lt;p&gt;I&amp;rsquo;m currently working on building a small computer, and want to add some 4-pin computer fans, running quietly at a fixed speed.&lt;/p&gt;
&lt;p&gt;This blog post is just a quick set of notes from prototyping, since it covers a few topics which I haven&amp;rsquo;t written about before.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-fan-pico-01.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-fan-pico-01_hu_4dad3fa46fdd88df.jpg 480w, https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-fan-pico-01_hu_90bd6349aef1a635.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;the-problem&#34;&gt;The problem
&lt;/h2&gt;&lt;p&gt;The speed of 4-pin computer fans can be controlled by varying the duty cycle on a 25 KHz PWM signal. This signal normally comes from a 4-pin case fan header on the motherboard, which will not be available in this situation. Rather than run the fans at 100%, I&amp;rsquo;m going to try to generate my own PWM signal.&lt;/p&gt;
&lt;p&gt;Two main considerations led me to choose to use a microcontroller for this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I&amp;rsquo;ll need some way to adjust the PWM duty cycle after building the circuit, because I don&amp;rsquo;t know which value will give the best trade-off between airflow and noise yet.&lt;/li&gt;
&lt;li&gt;Fans need a higher PWM duty cycle to start than they do to run. If I want to run the fans at a very low speed, then I&amp;rsquo;ll need them to ramp up on start-up, before slowing to the configured value.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;rsquo;s worth noting that I&amp;rsquo;m a complete beginner with microcontrollers. I&amp;rsquo;ve run some example programs on the Raspberry Pi Pico, but that&amp;rsquo;s it.&lt;/p&gt;
&lt;h2 id=&#34;first-attempt&#34;&gt;First attempt
&lt;/h2&gt;&lt;p&gt;I already had MicroPython running on my Raspberry Pi Pico, so that was my starting point.&lt;/p&gt;
&lt;p&gt;For a development environment, I installed the MicroPython plugin for PyCharm, since I use JetBrains IDE&amp;rsquo;s already for programming. Most guides for beginners suggest using Thonny.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-micropython-01.png&#34;
	width=&#34;2118&#34;
	height=&#34;1423&#34;
	srcset=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-micropython-01_hu_428fa4e00908988a.png 480w, https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-micropython-01_hu_37233e0e714529ea.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;148&#34;
		data-flex-basis=&#34;357px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;There are introductory examples on GitHub at &lt;a class=&#34;link&#34; href=&#34;https://github.com/raspberrypi/pico-micropython-examples&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;raspberrypi/pico-micropython-examples&lt;/a&gt; which showed me everything I needed to know. I was able to combine an ADC example and a PWM example within a few minutes.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;machine&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Pin&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PWM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ADC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;level_input&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ADC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;pwm_output&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PWM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Pin&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;27&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;timer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Timer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 25 KHz&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;pwm_output&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;freq&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;25000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;update_pwm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;timer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34; Update PWM duty cycle based on ADC input &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;duty&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;level_input&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;read_u16&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;pwm_output&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;duty_u16&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;duty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Start with 50% duty cycle for 2 seconds (to start fan)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;pwm_output&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;duty_u16&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;32768&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sleep&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Update from ADC input after that&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;timer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Timer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PERIODIC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;period&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;callback&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;update_pwm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On my oscilloscope, I could confirm that the PWM signal had a 25 KHz frequency, and that the code was adjusting the duty cycle as expected. When the analog input (above) is set to a high value, the PWM signal has a high duty cycle.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-pico-high-dutycycle.png&#34;
	width=&#34;800&#34;
	height=&#34;480&#34;
	srcset=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-pico-high-dutycycle_hu_9dded7a06ce7d1f9.png 480w, https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-pico-high-dutycycle_hu_65a40736c1383540.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;166&#34;
		data-flex-basis=&#34;400px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;When set to a low value, the PWM signal has a low duty cycle.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-pico-low-dutycycle.png&#34;
	width=&#34;800&#34;
	height=&#34;480&#34;
	srcset=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-pico-low-dutycycle_hu_bcd49ae4fb4c9751.png 480w, https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-pico-low-dutycycle_hu_c47ebcaef1bee3b1.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;166&#34;
		data-flex-basis=&#34;400px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;but-can-it-control-fans&#34;&gt;But can it control fans?
&lt;/h2&gt;&lt;p&gt;I wired up a PC fan to 12 V power, and also sent it this PWM signal, but the speed didn&amp;rsquo;t change. This was expected, since I knew that I would most likely need to convert the 3.3 V signal up to 5 V.&lt;/p&gt;
&lt;p&gt;I ran it through a 74LS04 hex inverter with VCC at 5 V, which did the trick. I could then adjust a potentiometer, and the fan would speed up or slow down.&lt;/p&gt;
&lt;p&gt;I captured the breadboard setup in Fritzing. Just note that there are floating inputs on the 74LS04 chip (not generally a good idea) and that the part is incorrectly labelled 74HC04, when the actual part I used was a 74LS04.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-fritzing-pico.png&#34;
	width=&#34;1755&#34;
	height=&#34;918&#34;
	srcset=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-fritzing-pico_hu_5d2b8229bb701295.png 480w, https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-fritzing-pico_hu_40b9db7e996e82ad.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;191&#34;
		data-flex-basis=&#34;458px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This shows a working setup, but it&amp;rsquo;s got more components than I would like. I decided to implement it a second time, on a simpler micro-controller which can work at 5 V directly.&lt;/p&gt;
&lt;h1 id=&#34;porting-to-the-attiny85&#34;&gt;Porting to the ATtiny85
&lt;/h1&gt;&lt;p&gt;For a second attempt, I tried using an ATtiny85. This uses the AVR architecture (of Arduino fame), which I&amp;rsquo;ve never looked at before.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-attiny-chip.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-attiny-chip_hu_d398c6f97c8562d0.jpg 480w, https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-attiny-chip_hu_e295bb15859c9d9e.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This chip is small, widely available, and can run at 5 V. I can also program it using the TL-866II+ rather than investing into the ecosystem with Arduino development boards or programmers.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-attiny-programming.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-attiny-programming_hu_df38f2c79cf5d026.jpg 480w, https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-attiny-programming_hu_f198c0384f152db1.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I found &lt;a class=&#34;link&#34; href=&#34;https://github.com/marceloaqno/4-Wire-FAN-Arduino/blob/master/ATtiny_PWM_Phase_Corret_25kHz.ino&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;GPL-licensed code by Marcelo Aquino&lt;/a&gt; for controlling 4-wire fans.&lt;/p&gt;
&lt;p&gt;After a few false starts trying to compile manually, I followed &lt;a class=&#34;link&#34; href=&#34;http://highlowtech.org/?p=1695&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this guide&lt;/a&gt; to get the ATtiny85 &amp;lsquo;board&amp;rsquo; definition loaded into the Arduino IDE.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-arduino-ide-export.png&#34;
	width=&#34;1682&#34;
	height=&#34;1548&#34;
	srcset=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-arduino-ide-export_hu_49e1c06123a22390.png 480w, https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-arduino-ide-export_hu_3167f6332f24cfce.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;108&#34;
		data-flex-basis=&#34;260px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;From there I was able to build and get an intel hex file, using the &amp;ldquo;Export compiled binary&amp;rdquo; feature.&lt;/p&gt;
&lt;h2 id=&#34;writing-fuses&#34;&gt;Writing fuses
&lt;/h2&gt;&lt;p&gt;The code assumes an 8 MHz clock. The Attiny85 ships from the factory with a &amp;ldquo;divide by 8&amp;rdquo; fuse active. This needs to be turned off, otherwise the clock will be 1 MHz. This involves setting some magic values, separate to the program code.&lt;/p&gt;
&lt;p&gt;I found these values using &lt;a class=&#34;link&#34; href=&#34;http://www.engbedded.com/fusecalc&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;a fuse calculator&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The factory default for this chip is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lfuse 0x62, hfuse 0xdf, efuse 0xff.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To disable the divide-by-8 clock but leave all other values default, this needs to be:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lfuse 0xe2, hfuse 0xdf, efuse 0xff.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I am using the &lt;a class=&#34;link&#34; href=&#34;https://gitlab.com/DavidGriffith/minipro/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;minipro&lt;/a&gt; open source tool to program the chip, via a TL-866II+ programmer. First, to get the fuses:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ minipro -p ATTINY85@DIP8 -r fuses.txt -c config
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Found TL866II+ 04.2.126 (0x27e)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Warning: Firmware is out of date.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Expected  04.2.132 (0x284)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Found     04.2.126 (0x27e)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Chip ID: 0x1E930B  OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Reading config... 0.00Sec  OK
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This returns the values expected in a text file.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lfuse = 0x62
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;hfuse = 0xdf
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;efuse = 0x00
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lock = 0xff
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I then set &lt;code&gt;lfuse = 0xe2&lt;/code&gt;, and wrote the values back with this command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ minipro -p ATTINY85@DIP8 -w fuses.txt -c config
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Found TL866II+ 04.2.126 (0x27e)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Warning: Firmware is out of date.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Expected  04.2.132 (0x284)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Found     04.2.126 (0x27e)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Chip ID: 0x1E930B  OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Writing fuses... 0.01Sec  OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Writing lock bits... 0.01Sec  OK
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;writing-code&#34;&gt;Writing code
&lt;/h2&gt;&lt;p&gt;Now the microcontroller is ready to accept the exported binary containing the program.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ minipro -s -p ATTINY85@DIP8 -w sketch_pwm.ino.tiny8.hex -f ihex
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Found TL866II+ 04.2.126 (0x27e)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Warning: Firmware is out of date.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Expected  04.2.132 (0x284)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Found     04.2.126 (0x27e)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Chip ID: 0x1E930B  OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Found Intel hex file.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Erasing... 0.01Sec OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Writing Code...  1.09Sec  OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Reading Code...  0.45Sec  OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Verification OK
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the chip fully programmed, I wired it up on a breadboard with 5 V power.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-attiny-breadboard.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-attiny-breadboard_hu_b938b2a0b8756667.jpg 480w, https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-attiny-breadboard_hu_ea92cb8e14a1ee0c.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Checking the output again, the signal was the correct amplitude this time, but the frequency does move around a bit. This is likely because I&amp;rsquo;m using the internal RC timing on the chip, which is not very accurate. My understanding is that anything near 25 KHz will work fine.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-avr-pwm.png&#34;
	width=&#34;800&#34;
	height=&#34;480&#34;
	srcset=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-avr-pwm_hu_87ca08745ee993a1.png 480w, https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-avr-pwm_hu_264e8f2db3868e38.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;166&#34;
		data-flex-basis=&#34;400px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;updates&#34;&gt;Updates
&lt;/h2&gt;&lt;p&gt;I made only one change to Marcelo&amp;rsquo;s code, which is to spin the fan at 50% for a few seconds before using the potentiometer-set value. This is to avoid any issues where the fans fail to start because I&amp;rsquo;ve set them to run at a very low PWM value.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *                         ATtiny85
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *                      -------u-------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *  RST - A0 - (D 5) --| 1 PB5   VCC 8 |-- +5V
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *                     |               |
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *        A3 - (D 3) --| 2 PB3   PB2 7 |-- (D 2) - A1  --&amp;gt; 10K Potentiometer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *                     |               | 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *        A2 - (D 4) --| 3 PB4   PB1 6 |-- (D 1) - PWM --&amp;gt; Fan Blue wire
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *                     |               |      
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *              Gnd ---| 4 GND   PB0 5 |-- (D 0) - PWM --&amp;gt; Disabled
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *                     -----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// normal delay() won&amp;#39;t work anymore because we are changing Timer1 behavior
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Adds delay_ms and delay_us functions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;util/delay.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Adds delay_ms and delay_us functions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Clock at 8mHz
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#define F_CPU 8000000  &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// This is used by delay.h library
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PWMPin&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// Only works with Pin 1(PB1)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PotPin&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;A1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;setup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;pinMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PWMPin&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;OUTPUT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// Phase Correct PWM Mode, no Prescaler
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// PWM on Pin 1(PB1), Pin 0(PB0) disabled
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 8Mhz / 160 / 2 = 25Khz
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;TCCR0A&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;_BV&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;COM0B1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;_BV&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;WGM00&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;TCCR0B&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;_BV&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;WGM02&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;_BV&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CS00&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// Set TOP and initialize duty cycle to 50%
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;OCR0A&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;160&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// TOP - DO NOT CHANGE, SETS PWM PULSE RATE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;OCR0B&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// duty cycle for Pin 1(PB1)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// initial bring-up: leave at 50% for 4 seconds
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;_delay_ms&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;loop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;in&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;out&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// follow potentiometer-set speed from there
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;analogRead&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PotPin&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;out&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;in&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1023&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;160&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;OCR0B&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;out&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;_delay_ms&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;200&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The wiring of the breadboard is shown below. The capacitor is 0.1 µF for decoupling.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-fritzing-attiny85.png&#34;
	width=&#34;918&#34;
	height=&#34;861&#34;
	srcset=&#34;https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-fritzing-attiny85_hu_e8fb3b27cf7cf014.png 480w, https://mike42.me/blog/2023-09-controlling-computer-fans-with-a-microcontroller/2023-09-fritzing-attiny85_hu_cc27e5187c0f23af.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;106&#34;
		data-flex-basis=&#34;255px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This is far more compact than the Raspberry Pi Pico prototype. I could also miniaturise it further by simply using surface-mount versions of the same components, where using an RP2040 microcontroller from the Pico directly on a custom board would incur some design effort.&lt;/p&gt;
&lt;h2 id=&#34;next-steps--lessons-learned&#34;&gt;Next steps &amp;amp; lessons learned
&lt;/h2&gt;&lt;p&gt;Although this project is simple, I had to learn quite a few things to prototype it successfully. Using a generic chip programmer like the TL-866II+ appears to be uncommon in the AVR world, and most online guides instead suggest repurposing an Arduino development board or using an Arduino ICSP programmer to program the Attiny85. I was glad to confirm that I could use my existing hardware instead of buying ecosystem-specific items which I would have no other use for. I find the development experience to be far better with the Raspberry Pi Pico, and that&amp;rsquo;s what I would be choosing for a more complex project.&lt;/p&gt;
&lt;p&gt;I also captured the breadboard wiring in Fritzing for this blog post. The diagrams are clearer than a photo of a breadboard, but I&amp;rsquo;m not confident that they communicate information about the circuit as well as alternative approaches. For future posts, I&amp;rsquo;ll return to using KiCad EDA for schematic capture, unless there is some reason to highlight the physical layout of a breadboard prototype.&lt;/p&gt;
&lt;p&gt;As a next step, I&amp;rsquo;ll be building a simple break-out PCB for a specific computer case to power the fans and supply a PWM signal, based on the ATtiny85 prototype shown here.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Converting my 65C816 computer project to 3.3 V</title>
        <link>https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v</link>
        <pubDate>Thu, 12 Jan 2023 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v</guid>
        <description>&lt;p&gt;I recently spent some time re-building my 65C816 computer project to run at 3.3 volts, instead of 5 volts which it used previously. This blog post covers some of the things I needed to take into consideration for the change.&lt;/p&gt;
&lt;p&gt;It involved making use of &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board&#34; &gt;options which I added when I designed this test board&lt;/a&gt;, as well as re-visiting all of the mistakes in that design.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v/2023-01-computer-01.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;889&#34;
	srcset=&#34;https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v/2023-01-computer-01_hu_c58c01012593322b.jpg 480w, https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v/2023-01-computer-01_hu_9b96e44b15584814.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;143&#34;
		data-flex-basis=&#34;345px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;re-cap-why-33-v-is-useful&#34;&gt;Re-cap: Why 3.3 V is useful
&lt;/h2&gt;&lt;p&gt;One of the &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-01-a-first-look-at-the-65c816-processor&#34; &gt;goals of this project&lt;/a&gt; is to build a modern computer which uses a 65C816 CPU, using only in-production parts.&lt;/p&gt;
&lt;p&gt;A lot of interesting retro chips run at 5 V, but it&amp;rsquo;s much easier to find modern components which run at 3.3 V. I can make use of these options without adding level-shifting if I can switch important buses and control signals to 3.3 V.&lt;/p&gt;
&lt;h2 id=&#34;rom&#34;&gt;ROM
&lt;/h2&gt;&lt;p&gt;The ROM chip is the most visible change, because the chip has a different footprint. When assembling this board for 5 V use, I used an AT28C256 Parallel EEPROM, in a PDIP-28 ZIF socket. I couldn&amp;rsquo;t find 3.3 V drop-in replacement for this, so I added a footprint for a SST39LF010 flash chip, which has a similar-enough interface.&lt;/p&gt;
&lt;p&gt;This was the first time I&amp;rsquo;ve soldered a surface-mount PLCC socket. I attempted to solder this with hot air, which was unsuccessful, so I instead cut the center of the socket out so that I could use a soldering iron. I then added a small square of 1000 GSM card (approx 1mm thick) as a spacer under the chip.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v/2023-01-computer-02.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v/2023-01-computer-02_hu_c796762cceea7c2.jpg 480w, https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v/2023-01-computer-02_hu_aeefee6ee6d4a32.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I also added a new &lt;code&gt;make&lt;/code&gt; target to build the system ROM for this chip, which involves padding the file to a larger size, and invoking &lt;code&gt;minipro&lt;/code&gt; with a different option so that it could write the file. I&amp;rsquo;m using a TL866II+ for programming, and adapter boards are available for programming PLCC-packaged chips.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ make flashrom_sst39lf010
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cp -f rom.bin rom_sst39lf010.bin
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;truncate -s 131072 rom_sst39lf010.bin
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;minipro -p &amp;#34;SST39LF010@PLCC32&amp;#34; -w rom_sst39lf010.bin
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Found TL866II+ 04.2.126 (0x27e)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Warning: Firmware is newer than expected.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Expected  04.2.123 (0x27b)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Found     04.2.126 (0x27e)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Chip ID OK: 0xBFD5
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Erasing... 0.40Sec OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Writing Code...  8.38Sec  OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Reading Code...  1.18Sec  OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Verification OK
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;uart&#34;&gt;UART
&lt;/h2&gt;&lt;p&gt;The UART chip is an NXP SC16C752B, which is 3.3 V or 5 V compatible. I rescued one of these from an adapter board (&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer&#34; &gt;previous experiment&lt;/a&gt;). This was my first time de-soldering a component with hot air gun. Hopefully it still works!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v/2023-01-computer-03.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v/2023-01-computer-03_hu_f1f2ec4da881cebf.jpg 480w, https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v/2023-01-computer-03_hu_ebf7bf2653d94362.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;My FTDI-based USB/UART adapter has a configuration jumper which I adjusted to 3.3 V.&lt;/p&gt;
&lt;h2 id=&#34;clock-reset-and-address-decode&#34;&gt;Clock, reset and address decode
&lt;/h2&gt;&lt;p&gt;I again used a MIC2775 supervisory IC for power-on reset, though the exact part was different. I previously used a MIC2275-46YM5 (4.6 V threshold), where the re-build used a MIC2275-31YM5 (3.1 V threshold).&lt;/p&gt;
&lt;p&gt;I needed a 1.8432 MHz oscillator for the UART. The 3.3 V surface-mount part I substituted in had a different footprint, which I had prepared for.&lt;/p&gt;
&lt;p&gt;I also prepared for this change by using an ATF22LV10 PLD for address decoding, which is both 3.3 V and 5 V compatible. The ATF22V10 which I used for earlier experiments works at 5 V only.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v/2023-01-computer-04.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v/2023-01-computer-04_hu_eafcb5fd6e53af7d.jpg 480w, https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v/2023-01-computer-04_hu_8e51dc1c8e67cb21.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;sd-card&#34;&gt;SD card
&lt;/h2&gt;&lt;p&gt;I installed the DEV-13743 SD card module more securely this time by soldering it in place and adding some double-sided tape as a spacer. This module is compatible with 3.3 V or 5 V.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v/2023-01-computer-05.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v/2023-01-computer-05_hu_e3aec93ba5b3a6b3.jpg 480w, https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v/2023-01-computer-05_hu_ced3650261280b91.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The level-shifting and voltage regulation on this module is now superfluous, so I could probably simplify things by adding an SD card slot and some resistors directly in a later revision.&lt;/p&gt;
&lt;h2 id=&#34;modifications&#34;&gt;Modifications
&lt;/h2&gt;&lt;p&gt;There are three errors in the board which I know about (&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board&#34; &gt;all described in my earlier blog post&lt;/a&gt;). This is my second time fixing them, so I tried to make sure the modifications were neat and reliable this time.&lt;/p&gt;
&lt;p&gt;Firstly, the flip-flop used as a clock divider is wired up incorrectly, so I cut a trace and run a wire under the board.&lt;/p&gt;
&lt;p&gt;Second, the reset button pin assignments are incorrect. Simply rotating the button worked on the previous board, but it wasn&amp;rsquo;t fitted securely. This time I cut one of the legs and ran a short wire under the board, and the modification is barely noticeable.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v/2023-01-computer-06.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;928&#34;
	srcset=&#34;https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v/2023-01-computer-06_hu_52ae5a1e49c3ebf5.jpg 480w, https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v/2023-01-computer-06_hu_9c685502bec7883e.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;137&#34;
		data-flex-basis=&#34;331px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Lastly, the address bus is wired incorrectly into the chip which selects I/O devices. I previously worked around this in software, but this time I cut two traces and ran two wires (the orange wires in the picture). I made an equivalent modification to the 5 V board, so that I could update the software and test it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v/2023-01-computer-07.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v/2023-01-computer-07_hu_a66eb31d9daf029d.jpg 480w, https://mike42.me/blog/2023-01-converting-my-65c816-computer-project-to-3-3-v/2023-01-computer-07_hu_1422b1f32164df61.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The wire I was using for these mods is far too thick and inflexible. I&amp;rsquo;ve added some 30 AWG silicon-insulated wire to my inventory for the next time I need to do this type of work, which should be more suitable.&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap-up
&lt;/h2&gt;&lt;p&gt;I transferred components from the old board, and attempted to boot it every time I made change. The &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-06-lets-implement-power-on-self-test-post&#34; &gt;power-on self test&lt;/a&gt; routine built in to the ROM showed that each new chip was being detected, and I soon had a working 65C816 test board again, now running at 3.3 V. I&amp;rsquo;m using my tiny &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-08-building-a-simple-power-supply-module&#34; &gt;linear power supply module&lt;/a&gt; to power it.&lt;/p&gt;
&lt;p&gt;I can now interface to a variety of chips which only run at 3.3 V. This opens up some interesting possibilities for adding peripherals, which I hope to explore in future blog posts.&lt;/p&gt;
&lt;p&gt;It will be more difficult to remove and re-program the ROM chip going forward though. This is hopefully not a problem, since can now run code from an SD card or serial connection as well (&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1&#34; &gt;part 1&lt;/a&gt;, &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-2&#34; &gt;part 2&lt;/a&gt;).&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Porting the Amiga bouncing ball demo to the NES</title>
        <link>https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes</link>
        <pubDate>Wed, 23 Nov 2022 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes</guid>
        <description>&lt;p&gt;Earlier this year, I ported the Amiga bouncing ball demo to the Nintendo Entertainment System. This is a video capture from a NES emulator.&lt;/p&gt;

      &lt;div
          style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
        &lt;iframe
          src=&#34;https://player.vimeo.com/video/773285272?dnt=0&#34;
            style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allow=&#34;fullscreen&#34;&gt;
        &lt;/iframe&gt;
      &lt;/div&gt;

&lt;p&gt;I completed this back in January, but I&amp;rsquo;m only publishing this blog post now, because I was considering entering it into a demo competition.&lt;/p&gt;
&lt;h2 id=&#34;how-it-works&#34;&gt;How it works
&lt;/h2&gt;&lt;p&gt;If you are familiar with NES development, then you will probably notice that there is nothing ground-breaking going on here. The ball is made up of 64 8x8 sprites, bouncing around the screen over a static background.&lt;/p&gt;
&lt;p&gt;There are two different versions of the ball in sprite memory, and with some palette swapping, this can be stretched to 4 frames of animation, just enough to make the ball appear to spin.&lt;/p&gt;
&lt;p&gt;There is enough sprite memory to extend this to 8 frames of animation without any banking tricks, but I would need to start again from scratch to achieve that.&lt;/p&gt;
&lt;h2 id=&#34;pre-rendered-3d&#34;&gt;Pre-rendered 3D
&lt;/h2&gt;&lt;p&gt;I drew the ball in Blender, with twice the number of segments required for the final image. This is a UV sphere with 8 rings, and 32 segments.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-blender-01.png&#34;
	width=&#34;3844&#34;
	height=&#34;2100&#34;
	srcset=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-blender-01_hu_f39ff1893542a6a5.png 480w, https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-blender-01_hu_103bcca6e00244af.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;183&#34;
		data-flex-basis=&#34;439px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I coloured each face with one of 4 colours, then rendered it with the Workbench renderer, which I had configured to use Flat lighting, no anti-aliasing, and the texture colour.&lt;/p&gt;
&lt;p&gt;I also tilted the ball.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-blender-02.png&#34;
	width=&#34;3844&#34;
	height=&#34;2100&#34;
	srcset=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-blender-02_hu_b3648aa8376b19fc.png 480w, https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-blender-02_hu_1712e083f64e021d.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;183&#34;
		data-flex-basis=&#34;439px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This gave me a crisp, high-resolution ball with solid colours.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-ball-rendered.png&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-ball-rendered_hu_e6d97d3193899161.png 480w, https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-ball-rendered_hu_b63e91df6d180a0.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;To test the idea, I processed this down to a 64x64 image on a transparent background. I need to substitute colours, so there is no antialiasing here.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-ball-scaled-1.png&#34;
	width=&#34;64&#34;
	height=&#34;64&#34;
	srcset=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-ball-scaled-1_hu_2e9c30b8e07f16d2.png 480w, https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-ball-scaled-1_hu_127600ef480270ea.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;100&#34;
		data-flex-basis=&#34;240px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I then wrote up a Python script to swap out colours to make the 4-frame pattern. Note that frames 3 and 4 are the same as frames 1 and 2, but with white and red swapped.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-ball-frame-0.png&#34;
	width=&#34;64&#34;
	height=&#34;64&#34;
	srcset=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-ball-frame-0_hu_23568b7d0311169e.png 480w, https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-ball-frame-0_hu_732c1a49e62e18d7.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;100&#34;
		data-flex-basis=&#34;240px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-ball-frame-1.png&#34;
	width=&#34;64&#34;
	height=&#34;64&#34;
	srcset=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-ball-frame-1_hu_6f4bca187cc3d267.png 480w, https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-ball-frame-1_hu_dfbc34987822ae6b.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;100&#34;
		data-flex-basis=&#34;240px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-ball-frame-2.png&#34;
	width=&#34;64&#34;
	height=&#34;64&#34;
	srcset=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-ball-frame-2_hu_70016d0cda03acad.png 480w, https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-ball-frame-2_hu_7a73604b8f5d1d09.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;100&#34;
		data-flex-basis=&#34;240px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-ball-frame-3.png&#34;
	width=&#34;64&#34;
	height=&#34;64&#34;
	srcset=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-ball-frame-3_hu_fb01b0af0efcf68d.png 480w, https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-ball-frame-3_hu_ab7e4f02901fedcd.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;100&#34;
		data-flex-basis=&#34;240px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I ran this through ImageMagick to convert it into a GIF preview.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;convert -delay 3.5 -loop 0 *.png animation.gif
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-animation.gif&#34;
	width=&#34;64&#34;
	height=&#34;64&#34;
	
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;100&#34;
		data-flex-basis=&#34;240px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The result appeared workable, so I went about making the same animation in a NES rom.&lt;/p&gt;
&lt;h2 id=&#34;nes-implmentation&#34;&gt;NES implmentation
&lt;/h2&gt;&lt;p&gt;On the NES, it&amp;rsquo;s not possible to create the spinning ball effect with palette changes only, because it would require four colours plus transparency. To overcome this, I split the image into two frames, each stored as two colours plus transparency, which is possible.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-sprite-sheet.png&#34;
	width=&#34;128&#34;
	height=&#34;128&#34;
	srcset=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-sprite-sheet_hu_bf148aac6b869476.png 480w, https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-sprite-sheet_hu_db1a58cbfcd6f235.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;100&#34;
		data-flex-basis=&#34;240px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;To start the code, I checked out a fresh copy of Brad Smith&amp;rsquo;s &lt;a class=&#34;link&#34; href=&#34;https://github.com/bbbradsmith/NES-ca65-example&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;NES example project&lt;/a&gt;, then deleted things that I didn&amp;rsquo;t need.&lt;/p&gt;
&lt;p&gt;When working with sprites on the NES, it is typical to store object attributes in RAM, then perform a DMA operation once per frame to copy this over to the Picture Processing Unit (PPU). For this project, I wanted to try setting up two different copies of the object attribute memory in RAM - one for each of the two rotations.&lt;/p&gt;
&lt;p&gt;This should allow me to set any of the four frames by choosing between two possible colour palettes, and two possible DMA source addresses. This worked, and the first milestone was a spinning ball.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-ball-fceux-1.png&#34;
	width=&#34;276&#34;
	height=&#34;298&#34;
	srcset=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-ball-fceux-1_hu_78b5dbb5f5bb35f.png 480w, https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-ball-fceux-1_hu_3244fc4635480933.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;92&#34;
		data-flex-basis=&#34;222px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Switching between two DMA sources did not save much effort in the end, because I still needed quite a lot of code to set the X/Y positions of 64 sprites each frame. I set up some assembler macros to help with this.&lt;/p&gt;
&lt;h2 id=&#34;physics-and-sound&#34;&gt;Physics and sound
&lt;/h2&gt;&lt;p&gt;I have &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective&#34; &gt;made one NES game before&lt;/a&gt;, and I was not happy with the physics. For this project, I wanted to do a bit better.&lt;/p&gt;
&lt;p&gt;For the X position, I use a fixed speed, and simple collision detection with left/right boundaries. The animation frame is calculated from the X position, so the ball changes rotation depending on which direction it is moving, just like the Amiga demo.&lt;/p&gt;
&lt;p&gt;The Y location of the ball is a simple loop, and follows the absolute value of a sine wave. I pre-computed this with some Python.&lt;/p&gt;
&lt;p&gt;My last project also had no sound, so I read up on the NES APU, and added some noise when the ball changes direction.&lt;/p&gt;
&lt;h2 id=&#34;development-setup&#34;&gt;Development setup
&lt;/h2&gt;&lt;p&gt;Since my last NES project, I have improved my development setup quite a bit. As always, I am using the &lt;code&gt;ca65&lt;/code&gt; assembler on Linux.&lt;/p&gt;
&lt;p&gt;Previously, I was using a text editor. I have since moved to &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-05-intellij-plugin-for-6502-assembly-language&#34; &gt;a custom 6502 assembly plugin&lt;/a&gt; on PyCharm, which allows me to quickly jump to definitions/usages. I developed this for my other 65C02 and 65C816 projects, which you can read about on this blog.&lt;/p&gt;
&lt;p&gt;When I click run, I&amp;rsquo;ve set up the project to assemble a NES ROM, then launch with &lt;code&gt;fceux&lt;/code&gt;, which has debugging features.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-nes-dev-setup.png&#34;
	width=&#34;1461&#34;
	height=&#34;893&#34;
	srcset=&#34;https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-nes-dev-setup_hu_31c6e2a542b5e061.png 480w, https://mike42.me/blog/2022-11-porting-the-amiga-bouncing-ball-demo-to-the-nes/2022-11-nes-dev-setup_hu_cdf3a0b8c11cb2f4.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;163&#34;
		data-flex-basis=&#34;392px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The debug features were previously only available on Windows builds of fceux, so when I made this demo, I was running the emulator via WINE. This has been added to the Linux builds as of &lt;a class=&#34;link&#34; href=&#34;https://fcex.com/web/pressrelease-2.5.0.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;v2.5.0&lt;/a&gt;, so I&amp;rsquo;ll most likely switch to that for my next project.&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap-up
&lt;/h2&gt;&lt;p&gt;I learn something new every time I write code for the NES, and it&amp;rsquo;s a lot of fun to make simple demos for these old systems. It&amp;rsquo;s also refreshing to create something standalone which I can explain through screenshots, instead of &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-03-lets-implement-preemptive-multitasking&#34; &gt;pages of assembly code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For those who do want to read pages of assembly code, though, this project is up on GitHub at &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/nes-ball-demo&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/nes-ball-demo&lt;/a&gt;.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Let’s make a bootloader – Part 2</title>
        <link>https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-2</link>
        <pubDate>Thu, 22 Sep 2022 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-2</guid>
        <description>&lt;p&gt;In &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1&#34; &gt;my previous blog post&lt;/a&gt;, I wrote about loading and executing a 512 byte program from an SD card for my 65C816 computer project.&lt;/p&gt;
&lt;p&gt;For part 2, I&amp;rsquo;ll look at what it takes to turn this into a bootloader, which can load a larger program from the SD card. I want the bootloader to control where to read data from, and how much data to load, which will allow me to change the program structure/size without needing to update the code on ROM.&lt;/p&gt;
&lt;h2 id=&#34;getting-more-data&#34;&gt;Getting more data
&lt;/h2&gt;&lt;p&gt;The code in my previous post used software interrupts to print some text to the console, and my first challenge was to implement a similar routine for loading additional data from external storage.&lt;/p&gt;
&lt;p&gt;The interface from the bootloader is quite simple: it sets a few registers to specify the source (a block number), destination memory address, and number of blocks to read, then  triggers a software interrupt. The current implementation can read up to 64 KiB of data from the SD card each time it is called.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;ROM_READ_DISK&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$03&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; other stuff ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$0000                      ; lower 2 bytes of destination address
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$01                        ; block number
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;ldy&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$10                        ; number of blocks to read - 8 KiB
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;cop&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ROM_READ_DISK&lt;/span&gt;               &lt;span class=&#34;c1&#34;&gt;; read kernel to RAM
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;higher-memory-addresses&#34;&gt;Higher memory addresses
&lt;/h2&gt;&lt;p&gt;To load data in to higher banks (memory addresses above &lt;code&gt;$ffff&lt;/code&gt;, I set the data bank register.&lt;/p&gt;
&lt;p&gt;I needed to update a lot of my code to use absolute long (24-bit) addressing for I/O access, where it was previously using absolute (16-bit) addressing, for example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$0c00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In my assembler, &lt;code&gt;ca65&lt;/code&gt;, I already use the &lt;code&gt;a:&lt;/code&gt; prefix to specify 16-bit addressing. I learned here that I can use the &lt;code&gt;f:&lt;/code&gt; prefix for 24-bit addressing.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;$0c00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Without doing this, the assembler chooses the smallest possible address size. This is fine in a 65C02 system, but I find it less helpful on the 65C816, where the meaning of a 16-bit address depends on the data bank register, and the meaning of an 8-bit address depends on the direct page register.&lt;/p&gt;
&lt;h2 id=&#34;new-bootloader&#34;&gt;New bootloader
&lt;/h2&gt;&lt;p&gt;With the ROM code sorted out, I went on to write the new bootloader.&lt;/p&gt;
&lt;p&gt;This new code sets the data bank address, then uses a software interrupt to load 8 KiB of data to address &lt;code&gt;$010000&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; boot.s: 512-byte bootloader. This utilizes services defined in ROM.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;ROM_PRINT_STRING&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$02&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;ROM_READ_DISK&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$03&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.segment&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;CODE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;.a16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;.i16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;code_start&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;code_start:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;; load kernel
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#loading_kernel             ; Print loading message (kernel)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;cop&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ROM_PRINT_STRING&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;phb&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; Save current data bank register
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;na&#34;&gt;.a8&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; Set data bank register to 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;sep&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%00100000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$01
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;pha&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;plb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;plp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;.a16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$0000                      ; lower 2 bytes of destination address
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$01                        ; block number
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;ldy&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$10                        ; number of blocks to read - 8 KiB
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;cop&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ROM_READ_DISK&lt;/span&gt;               &lt;span class=&#34;c1&#34;&gt;; read kernel to RAM
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;plb&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; Restore previous data bank register
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#boot                       ; Print boot message
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;cop&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ROM_PRINT_STRING&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;jml&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$010000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;loading_kernel:&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;.asciiz&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Loading kernel\r\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;boot:&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;.asciiz&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Booting\r\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.segment&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;SIGNATURE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;wdm&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$42&lt;/span&gt;                         &lt;span class=&#34;c1&#34;&gt;; Ensure x86 systems don&amp;#39;t recognise this as bootable.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The linker configuration for the bootloader is unchanged from part 1.&lt;/p&gt;
&lt;h2 id=&#34;a-placeholder-kernel&#34;&gt;A placeholder kernel
&lt;/h2&gt;&lt;p&gt;The bootloader needed some code to load. I don&amp;rsquo;t have any real operating system to load, so I created the “Hello World” of kernels to work with in the meantime.&lt;/p&gt;
&lt;p&gt;This is the simplest possible code I can come up with to test the bootloader. This assembles to 3 machine-language instructions, which occupy just 6 bytes. It is also is position-independent, and will work from any memory bank.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; kernel_tmp.s: A temporary placeholder kernel to test boot process.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;ROM_PRINT_CHAR&lt;/span&gt;   &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.segment&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;CODE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;.a16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;.i16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#&amp;#39;z&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;cop&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ROM_PRINT_CHAR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;stp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The linker configuration for this, &lt;code&gt;kernel_tmp.cfg&lt;/code&gt;, creates an 8 KiB binary.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;MEMORY {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ZP:     start = $00,    size = $0100, type = rw, file = &amp;#34;&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    RAM:    start = $0200,  size = $7e00, type = rw, file = &amp;#34;&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    PRG:    start = $e000,  size = $2000, type = ro, file = %O, fill = yes, fillval = $00;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SEGMENTS {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ZEROPAGE: load = ZP,  type = zp;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    BSS:      load = RAM, type = bss;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    CODE:     load = PRG, type = ro,  start = $e000;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The commands I used to assemble and link the bootloader are:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ca65 --feature string_escapes --cpu 65816 --debug-info boot.s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ld65 -o boot.bin -C boot.cfg boot.o
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The commands I used to assemble and link the placeholder kernel are:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ca65 --feature string_escapes --cpu 65816 --debug-info kernel_tmp.s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ld65 -o kernel_tmp.bin -C kernel_tmp.cfg kernel_tmp.o
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I assembled the final disk image by concatenating these files together.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat bootloader/boot.bin kernel_tmp/kernel_tmp.bin &amp;gt; disk.img
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I used the GNOME disk utility to write the image to an SD card, which helpfully reports that I&amp;rsquo;m not using all of the available space.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-2/2022-09-sd-boot-gnome.png&#34;
	width=&#34;1046&#34;
	height=&#34;568&#34;
	srcset=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-2/2022-09-sd-boot-gnome_hu_dff50e4393be381a.png 480w, https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-2/2022-09-sd-boot-gnome_hu_827049d6dd2bbef1.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;184&#34;
		data-flex-basis=&#34;441px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;result&#34;&gt;Result
&lt;/h2&gt;&lt;p&gt;It took me many attempts to get the ROM code right, but this did work. This screen capture shows the test kernel source code on the left, which is being executed at the end of the boot-up process.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-2/2022-09-sd-boot-01.png&#34;
	width=&#34;2056&#34;
	height=&#34;1098&#34;
	srcset=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-2/2022-09-sd-boot-01_hu_9d8663164af82827.png 480w, https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-2/2022-09-sd-boot-01_hu_69bb707fc208d798.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;187&#34;
		data-flex-basis=&#34;449px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;If I wanted to load the kernel from within a proper filesystem on the SD card (eg. FAT32), then I would need to update the starting block in the bootloader (hard-coded to &lt;code&gt;1&lt;/code&gt; at the moment).&lt;/p&gt;
&lt;p&gt;The limitations of this mechanism are that the kernel needs to be stored contiguously, be sector-aligned, and located within the first 64 MiB of the SD card.&lt;/p&gt;
&lt;h2 id=&#34;speed-increase&#34;&gt;Speed increase
&lt;/h2&gt;&lt;p&gt;This was the first time that I wrote code for this system and needed to wait for it to execute. The CPU was clocked at just 921.6 KHz. My SPI/SD card code was also quite generic, and was optimised for ease of debugging rather than execution speed.&lt;/p&gt;
&lt;p&gt;I improved this from two angles. My &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board&#34; &gt;65C816 test board&lt;/a&gt; allows me to use a different clock speed for the CPU and UART chip, so I sped the CPU up to 4 MHz by dropping in an 8 MHz oscillator (it is halved to produce a two-phase clock). As I sped this up, I also needed to add more retries to the SD card initialisation code, since it does not respond immediately on power-up.&lt;/p&gt;
&lt;p&gt;I also spent a lot of time hand-optimising the assembly language routine to receive a 512-byte block of data from the SD card. There is room to speed this up further, but it&amp;rsquo;s fast enough to not be a problem for now.&lt;/p&gt;
&lt;p&gt;I had hoped to load an in-memory filesystem (ramdisk) alongside the test kernel, but I&amp;rsquo;ve deferred this until I can compress it, since reading from SD card is still quite slow.&lt;/p&gt;
&lt;h2 id=&#34;a-debugging-detour&#34;&gt;A debugging detour
&lt;/h2&gt;&lt;p&gt;Writing bare-metal assembly with no debugger is very rewarding when it works, and very frustrating when there is something I&amp;rsquo;m not understanding correctly.&lt;/p&gt;
&lt;p&gt;I ran into one debugging challenge here which is obvious in hindsight, but I almost couldn&amp;rsquo;t solve at the time.&lt;/p&gt;
&lt;p&gt;This code is (I assure you) a bug-free way to print one hex character, assuming the code is loaded in bank 0. I was using this to hexdump the code I was loading into memory.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.a8&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; Accumulator is 8-bit
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.i16&lt;/span&gt;                            &lt;span class=&#34;c1&#34;&gt;; Index registers are 16-bit
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#0                          ; A is 0 for example
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$0f                        ; Take low-nibble only
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;tax&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; Transfer to X
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;hex_chars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;X&lt;/span&gt;              &lt;span class=&#34;c1&#34;&gt;; Load hex char for X
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;uart_print_char&lt;/span&gt;             &lt;span class=&#34;c1&#34;&gt;; Print hex char for X
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;hex_chars:&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;.byte&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;d&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The problem I had was that if the data bank register was 0, this would print ASCII character &amp;lsquo;0&amp;rsquo; as expected. But if the data bank register was 1, it would print some binary character.&lt;/p&gt;
&lt;p&gt;Nothing in this code &lt;em&gt;should&lt;/em&gt; be affected by the data bank register, so I went through a methodical debugging process to try to list and check all of my assumptions. At one point, I even checked that the assembler was producing the correct opcode for this &lt;code&gt;lda&lt;/code&gt; addressing mode (there are &lt;a class=&#34;link&#34; href=&#34;https://cc65.github.io/mailarchive/2013-01/11059.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;red herrings&lt;/a&gt; on the mailing lists about this).&lt;/p&gt;
&lt;p&gt;I was able to narrow down the problem by writing different variations of the code which should all do the same thing, but used different opcodes to get there. This quickly revealed that it was the &lt;code&gt;tax&lt;/code&gt; instruction which did not work as I thought, after finding that I could get the code working if I avoided it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.a8&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; Accumulator is 8-bit
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.i16&lt;/span&gt;                            &lt;span class=&#34;c1&#34;&gt;; Index registers are 16-bit
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#0                          ; X is 0 for example
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;hex_chars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;X&lt;/span&gt;              &lt;span class=&#34;c1&#34;&gt;; Load hex char for X
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;uart_print_char&lt;/span&gt;             &lt;span class=&#34;c1&#34;&gt;; Print hex char for X
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;hex_chars:&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;.byte&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;d&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;My first faulty assumption was that if I set the accumulator to 0, then transferring the accumulator value to X would set the X register to 0 as well.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.a8&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; Accumulator is 8-bit
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.i16&lt;/span&gt;                            &lt;span class=&#34;c1&#34;&gt;; Index registers are 16-bit
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#0                          ; Accumulator is 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;tax&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; X is 0?
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On this architecture, there are two bits of CPU status register which specify the size of the accumulator and index registers. When the accumulator is 8-bits, only the lower 8-bits of the 16-bit value are set by &lt;code&gt;lda&lt;/code&gt;. I hadn&amp;rsquo;t realised that when the index registers are set to 16-bit, the &lt;code&gt;tax&lt;/code&gt; instruction transfers all 16 bits of the accumulator to the X register (regardless of the accumulator size), which was causing surprising results.&lt;/p&gt;
&lt;p&gt;Far away from the bug-free code I was focusing on, I had used a lazy method to set the data bank register, which involved setting the accumulator to &lt;code&gt;$0101&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;My second faulty assumption was that the data bank register was involved at all - in fact &lt;code&gt;lda #$0101&lt;/code&gt; would have been enough to break the later code.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.a16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$0101                      ; Set data bank register to 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;pha&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;plb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;plb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To fix this, when switching to an 8-bit accumulator, I now zero out the high 8-bits.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.a8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#0                          ; zero out the B accumulator
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;xba&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;alternative-boot-method&#34;&gt;Alternative boot method
&lt;/h2&gt;&lt;p&gt;I also added an option to boot from serial, based on my implementation of an XMODEM receive function for the &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer&#34; &gt;6502 processor&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is a bit like &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Preboot_Execution_Environment&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;PXE boot&lt;/a&gt; for retro computers. From a program such as &lt;code&gt;minicom&lt;/code&gt;, you tell the ROM to boot from serial, then upload the kernel via an XMODEM send. It loads up to 64KiB to bank 1 (the same location as the bootloader on the SD card would place it), then executes it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-2/2022-09-serial-boot-65c816.png&#34;
	width=&#34;1576&#34;
	height=&#34;1066&#34;
	srcset=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-2/2022-09-serial-boot-65c816_hu_5bace2cb7b97a11b.png 480w, https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-2/2022-09-serial-boot-65c816_hu_4ea30d14e45a60fa.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;147&#34;
		data-flex-basis=&#34;354px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This is an important option for testing, since it&amp;rsquo;s a fast way to get some code running while I don&amp;rsquo;t have an operating system, and writing to an SD card from a modern computer is not a fast process. It may also be an important fallback if I need to troubleshoot SD card routines.&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap-up
&lt;/h2&gt;&lt;p&gt;Previously, I needed to use a ROM programmer to load code onto this computer. I can now use an SD card or serial connection, and have a stable interface for the bootstrapping code to access some minimal services provided by the ROM.&lt;/p&gt;
&lt;p&gt;It is also the first time I&amp;rsquo;m running code outside of bank 0, breaking through the 64 KiB limit of the classic 6502. There is an entire megabyte of RAM on this test board.&lt;/p&gt;
&lt;p&gt;Of course, this computer still does nothing useful, but at least it now controlled by an SD card rather than flashing a ROM. On the hardware side of the project, this will help me to convert the design from 5 V to 3.3 V. I&amp;rsquo;ll need to convert the ROM to a PLCC-packaged flash chip for that, which is not something I&amp;rsquo;ll want to be programming frequently.&lt;/p&gt;
&lt;p&gt;As far as software goes, my plan is to work on some more interesting demo programs, so that I can start to build a library of open source 65C816 code to work with. The hardware design, software and emulator for this computer can be found on GitHub, at &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/65816-computer&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/65816-computer&lt;/a&gt;.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Let&#39;s make a bootloader - Part 1</title>
        <link>https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1</link>
        <pubDate>Thu, 01 Sep 2022 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1</guid>
        <description>&lt;p&gt;I&amp;rsquo;ve been working on a homebrew computer based on the 16-bit 65C816 CPU. All of my test programs so far have run from an &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/EEPROM&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;EEPROM&lt;/a&gt; chip, which I need to remove and re-program each time I need to make a change.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1/2022-08-rom-programming.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1/2022-08-rom-programming_hu_3f0b38c2edde397.jpg 480w, https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1/2022-08-rom-programming_hu_b0e7df0159f4a583.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Plenty of retro systems ran &lt;em&gt;all&lt;/em&gt; of their programs from ROM, but I only want to use it for bootstrapping this computer. I&amp;rsquo;ve got 8 KiB of space for ROM-based programs in the memory map, which should be plenty to &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-06-lets-implement-power-on-self-test-post&#34; &gt;check the hardware&lt;/a&gt; and load software from disk.&lt;/p&gt;
&lt;p&gt;In this two-part blog post, I&amp;rsquo;ll take a look at handing over control from the ROM to a program loaded from an SD card.&lt;/p&gt;
&lt;h2 id=&#34;technical-background&#34;&gt;Technical background
&lt;/h2&gt;&lt;p&gt;I did some quick reading about the process for bootstrapping a PC during the 16-bit era. My homebrew computer is a completely different architecture to an IBM-compatible PC, but I&amp;rsquo;m planning to follow a few of the conventions from this ecosystem, since I&amp;rsquo;ll have some similar challenges.&lt;/p&gt;
&lt;p&gt;The best resources on this topic are aimed at bootloader developers, such as this &lt;a class=&#34;link&#34; href=&#34;https://en.wikibooks.org/wiki/X86_Assembly/Bootloaders&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;wikibooks page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For a disk to be considered bootable, the first 512-byte sector needs to end with hex &lt;code&gt;0xAA55&lt;/code&gt; (little-endian) . This is &lt;code&gt;01010101&lt;/code&gt; &lt;code&gt;10101010&lt;/code&gt; in binary (&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-06-lets-implement-power-on-self-test-post&#34; &gt;a great test pattern!&lt;/a&gt;). My system is not x68-based, so I&amp;rsquo;ll store a different value there.&lt;/p&gt;
&lt;p&gt;If a disk is bootable, then the BIOS will transfer the 512 byte boot sector to &lt;code&gt;$7C00&lt;/code&gt; and jump to it. The only assumption that the BIOS seems to make about the bootloader structure is that it starts with executable code. I&amp;rsquo;ll do the same on my system.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s worth noting that the first sector may also contain data structures for a filesystem or partitioning scheme, and it&amp;rsquo;s up to the bootloader code to work around that. For now, my SD card will contain &lt;em&gt;only&lt;/em&gt; a bootloader, which does simplify things a bit.&lt;/p&gt;
&lt;p&gt;Most bootloaders will then make a series of BIOS calls via software &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Interrupt&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;interrupts&lt;/a&gt;, which enables them produce text output or load additional data from disk. This is where I&amp;rsquo;ll have the biggest challenge, since my ROM has no stable interface for a bootloader to call.&lt;/p&gt;
&lt;h2 id=&#34;re-visiting-sd-card-handling&#34;&gt;Re-visiting SD card handling
&lt;/h2&gt;&lt;p&gt;My first task was to load the bootloader itself from SD card, storing the first 512 bytes from the disk to RAM, at address &lt;code&gt;$7C00&lt;/code&gt; onwards. This should be straightforward, since I have working &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer&#34; &gt;6502 assembly routines for reading from an SD card&lt;/a&gt;, and I&amp;rsquo;ve added a port for an SD card module to &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board&#34; &gt;my 65C816 test board&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1/2022-08-sd-hardware.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1/2022-08-sd-hardware_hu_c34b1948640b14a9.jpg 480w, https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1/2022-08-sd-hardware_hu_e9820b6dda0108e8.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I came up with a routine which prints the contents of the boot sector, then prompts for whether to execute it. My ROM code is not checking the signature at this stage, and is not aware that the boot sector in this screen capture contains x86 machine code within a &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system#Bootsector&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;FAT32 boot sector&lt;/a&gt;, but this is a good start.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1/2022-08-sd-result.png&#34;
	width=&#34;2800&#34;
	height=&#34;1750&#34;
	srcset=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1/2022-08-sd-result_hu_1df7703215398d64.png 480w, https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1/2022-08-sd-result_hu_4a1e4836cc0cb37d.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;160&#34;
		data-flex-basis=&#34;384px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;It took quite a few revisions to get this working, since my old 65C02 code for reading from SD produced strange output on this system. On my 65C816 test board, it showed &lt;em&gt;almost&lt;/em&gt; the right values, but it was jumbled up, and mixed with SPI fill bytes (&lt;code&gt;$FF&lt;/code&gt;). The below screen capture shows a diff between the expected and actual output of the ROM.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1/2022-08-sd-incorrect.png&#34;
	width=&#34;3840&#34;
	height=&#34;2160&#34;
	srcset=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1/2022-08-sd-incorrect_hu_840148e7c736f637.png 480w, https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1/2022-08-sd-incorrect_hu_8a4d67a81833de94.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;After a long process to rule out other programming and hardware errors, I finally noticed that I was writing the data starting from address &lt;code&gt;$0104&lt;/code&gt;, which was never going to work. The default stack pointer on this CPU is &lt;code&gt;$01ff&lt;/code&gt; and grows down, so writing 512 bytes to &lt;code&gt;$0104&lt;/code&gt; would always corrupt the stack after a few hundred bytes.&lt;/p&gt;
&lt;p&gt;At this stage I was using the assembler to statically allocate a 512 byte space for IO. It appeared in code like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.segment&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;BSS&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;io_block_id:&lt;/span&gt;              &lt;span class=&#34;na&#34;&gt;.res&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;io_buffer:&lt;/span&gt;                &lt;span class=&#34;na&#34;&gt;.res&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;512&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The error was in the linker configuration, which I updated to start assigning RAM addresses from &lt;code&gt;$0200&lt;/code&gt; onwards.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; MEMORY {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     ZP:     start = $00,    size = $0100, type = rw, file = &amp;#34;&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gd&#34;&gt;-    RAM:    start = $0100,  size = $7e00, type = rw, file = &amp;#34;&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+    RAM:    start = $0200,  size = $7d00, type = rw, file = &amp;#34;&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;     PRG:    start = $e000,  size = $2000, type = ro, file = %O, fill = yes, fillval = $00;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1/2022-08-sd-correct.png&#34;
	width=&#34;3840&#34;
	height=&#34;2160&#34;
	srcset=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1/2022-08-sd-correct_hu_f61c05cc9c251cea.png 480w, https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1/2022-08-sd-correct_hu_6ee54bc77d639f2f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The full SD card handling code is too long to post in this blog, but now allows any 512-byte segment from the first 32 MB of the SD card (identified by a 16-bit segment ID) to be loaded into an arbitrary memory address.&lt;/p&gt;
&lt;h2 id=&#34;making-an-api&#34;&gt;Making an API
&lt;/h2&gt;&lt;p&gt;My next challenge was to define an API for the bootloader to call into the ROM to perform I/O.&lt;/p&gt;
&lt;p&gt;I considered using a jump table, but decided to use the &lt;code&gt;cop&lt;/code&gt; instruction instead. This triggers a software interrupt on the 65C816, and has parallels to how the &lt;code&gt;int&lt;/code&gt; instruction is used to trigger BIOS routines on x86 systems.&lt;/p&gt;
&lt;p&gt;I defined a quick API for four basic routines, passing data via registers.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;print char&lt;/li&gt;
&lt;li&gt;read char&lt;/li&gt;
&lt;li&gt;print string&lt;/li&gt;
&lt;li&gt;load data from storage&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The caller would need to set some registers, then call &lt;code&gt;cop&lt;/code&gt; from assembly language. Any return data would also be passed via registers.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;cop&lt;/code&gt; instruction takes a one-byte operand, which in this case specifies the ID of the function to call.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;cop&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To prove that the interface would work, I implemented just the routine for printing strings.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; interrupt.s: Handling of software interrupts, the interface into the ROM for
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; software (eg. bootloaders)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Usage: Set registers and use &amp;#39;cop&amp;#39; to trigger software interrupt.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Eg:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;;   ldx #&amp;#39;a&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;;   cop ROM_PRINT_CHAR
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; CPU should be in native mode with all registers 16-bit.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.import&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;uart_printz&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;uart_print_char&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.export&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;cop_handler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.export&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ROM_PRINT_CHAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ROM_READ_CHAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ROM_PRINT_STRING&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ROM_READ_DISK&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Routines available in ROM via software interrupts.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Print one ASCII char.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;;   A is char to print
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;ROM_PRINT_CHAR&lt;/span&gt;   &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Read one ASCII char.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;;   Returns typed character in A register
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;ROM_READ_CHAR&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$01&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Print a null-terminated ASCII string.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;;   X is address of string, use data bank register for addresses outside bank 0.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;ROM_PRINT_STRING&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$02&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Read data from disk to RAM in 512 byte blocks.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;;   X is address to write to, use data bank register for addresses outside bank 0.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;;   A is low 2 bytes of block number
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;;   Y is number of blocks to read
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;ROM_READ_DISK&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$03&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.segment&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;CODE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; table of routines
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;cop_routines:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;rom_print_char_handler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;rom_read_char_hanlder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;rom_print_string_handler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;rom_read_disk_handler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;cop_handler:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;.a16&lt;/span&gt;                            &lt;span class=&#34;c1&#34;&gt;; use 16-bit accumulator and index registers
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;na&#34;&gt;.i16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;rep&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%00110000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;; Save caller context to stack
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;pha&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; Push A, X, Y
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;phx&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;phy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;phb&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; Push data bank, direct register
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;phd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;; Set up stack frame for COP handler
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;tsc&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; WIP set direct register to equal stack pointer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;sec&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;sbc&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#cop_handler_local_vars_size
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;tcs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;phd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;tcd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;caller_k&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;15&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;caller_ret&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;13&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;caller_p&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;12&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;caller_a&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;caller_x&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;caller_y&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;caller_b&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;caller_d&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;cop_call_addr&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;; set up 24 bit pointer to COP instruction
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;frame_base&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;caller_ret&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;dex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;dex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;stx&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;frame_base&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;cop_call_addr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;.a8&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; Use 8-bit accumulator
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;sep&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%00100000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;frame_base&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;caller_k&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;frame_base&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;cop_call_addr&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;.a16&lt;/span&gt;                            &lt;span class=&#34;c1&#34;&gt;; Revert to 16-bit accumulator
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;na&#34;&gt;rep&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%00100000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;; load COP instruction which triggered this interrupt to figure out routine to run
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;frame_base&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;cop_call_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;xba&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; interested only in second byte
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%00000011                  ; mask down to final two bits (there are only 4 valid functions at the moment)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;asl&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; multiply by 2 to index into table of routines
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;tax&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;cop_routines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;X&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;; Remove stack frame for COP handler
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;pld&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;tsc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;clc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;adc&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#cop_handler_local_vars_size
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;tcs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;; Restore caller context from stack, reverse order
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;pld&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; Pull direct register, data bank
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;plb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;ply&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; Pull Y, X, A
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;plx&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;pla&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;rti&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;cop_handler_local_vars_size&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;frame_base&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;rom_print_char_handler:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#aa
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;uart_printz&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;rts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;rom_read_char_hanlder:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#bb
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;uart_printz&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;rts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;rom_print_string_handler:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;; Print string from X register
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;frame_base&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;caller_x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;uart_printz&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;rts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;rom_read_disk_handler:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#cc
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;uart_printz&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;rts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;aa:&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;.asciiz&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Not implemented A\r\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;bb:&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;.asciiz&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Not implemented B\r\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;cc:&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;.asciiz&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Not implemented C\r\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This snippet is quite dense, and uses several features which are new to the 65C816, not just the &lt;code&gt;cop&lt;/code&gt; instruction.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m relocating the direct page to use as a &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Call_stack&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;stack frame&lt;/a&gt;, which is an idea I got from reading the output of the WDC 65C816 C compiler. Pointers are much easier to work with on the direct page.&lt;/p&gt;
&lt;p&gt;This is the first snippet I&amp;rsquo;ve shared which uses a 24-bit pointer, via &amp;ldquo;direct page, indirect long&amp;rdquo; addressing. The pointer is used to load the instruction which triggered the interrupt, so that the code can figure out which function to call.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;frame_base&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;cop_call_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This snippet is also the first time I&amp;rsquo;ve used the jump to subroutine instruction (&lt;code&gt;jsr&lt;/code&gt;) with the &amp;ldquo;absolute indirect, indexed with X&amp;rdquo; address mode. On the 65C02, I could only use this addressing mode on the &lt;code&gt;jmp&lt;/code&gt; instruction. The only example of that on this blog is &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-11-building-a-hardware-interrupt-controller&#34; &gt;also an interrupt handling example&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;cop_routines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;X&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;the-hello-world-of-bootloaders&#34;&gt;The &amp;ldquo;Hello World&amp;rdquo; of bootloaders
&lt;/h2&gt;&lt;p&gt;My next goal was to load a small program from disk, and show that it can call routines from the ROM. For now it is just a program on the boot sector on an SD card, which demonstrates that the new software interrupt API works.&lt;/p&gt;
&lt;p&gt;This assembly file &lt;code&gt;boot.s&lt;/code&gt; prints out two strings, so that I can be sure that the ROM is returning control back to the bootloader after a software interrupt completes.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;ROM_PRINT_STRING&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$02&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.segment&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;CODE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;.a16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;.i16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#test_string_1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;cop&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ROM_PRINT_STRING&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#test_string_2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;cop&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ROM_PRINT_STRING&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;stp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;test_string_1:&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;.asciiz&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Test 1\r\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;test_string_2:&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;.asciiz&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Test 2\r\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.segment&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;SIGNATURE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;wdm&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$42&lt;/span&gt;                         &lt;span class=&#34;c1&#34;&gt;; Ensure x86 systems don&amp;#39;t recognise this as bootable.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The linker configuration which goes with this is &lt;code&gt;boot.cfg&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;MEMORY {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ZP:     start = $00,    size = $0100, type = rw, file = &amp;#34;&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    RAM:    start = $7e00,  size = $0200, type = rw, file = &amp;#34;&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    PRG:    start = $7c00,  size = $0200, type = rw, file = %O, fill = yes, fillval = $00;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SEGMENTS {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ZEROPAGE:   load = ZP,  type = zp;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    BSS:        load = RAM, type = bss;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    CODE:       load = PRG, type = rw,  start = $7c00;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    SIGNATURE:  load = PRG, type = rw,  start = $7dfe;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The commands to assemble and link this are:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ca65 --feature string_escapes --cpu 65816 boot.s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ld65 -o boot.bin -C boot.cfg boot.o
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This produces a 512 byte file, which I wrote to SD card.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1/2022-08-sd-boot-example.png&#34;
	width=&#34;2710&#34;
	height=&#34;1750&#34;
	srcset=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1/2022-08-sd-boot-example_hu_9cf027f11b5f5981.png 480w, https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1/2022-08-sd-boot-example_hu_d2333e4b8631b493.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;154&#34;
		data-flex-basis=&#34;371px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This is the first time this computer is running code from RAM, which is an important milestone for this project.&lt;/p&gt;
&lt;h2 id=&#34;editor-improvements&#34;&gt;Editor improvements
&lt;/h2&gt;&lt;p&gt;I needed to do some work on my &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/6502-assembly-intellij&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;6502 assembly plugin for IntelliJ&lt;/a&gt; during this process, since it didn&amp;rsquo;t understand the square brackets used for the long address modes.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;frame_base&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;cop_call_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While I was fixing this, I also implemented an auto-format feature. This saves me the manual effort of lining up all the comments in a column, as is typical in assembly code.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1/2022-08-21-editor-formatting.gif&#34;
	width=&#34;728&#34;
	height=&#34;384&#34;
	
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;189&#34;
		data-flex-basis=&#34;455px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Lastly, I added support for jumping to unnamed labels, which are a &lt;code&gt;ca65&lt;/code&gt;-specific feature.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-09-lets-make-a-bootloader-part-1/2022-08-21-editor-labels.gif&#34;
	width=&#34;697&#34;
	height=&#34;374&#34;
	
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;186&#34;
		data-flex-basis=&#34;447px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next steps
&lt;/h2&gt;&lt;p&gt;In the second half of this blog post, I&amp;rsquo;ll get the bootloader to load a larger program from the SD card. I&amp;rsquo;m hoping to allow the bootloader to control how much code to load, and where to load it from.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Building a simple power supply module</title>
        <link>https://mike42.me/blog/2022-08-building-a-simple-power-supply-module</link>
        <pubDate>Thu, 18 Aug 2022 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2022-08-building-a-simple-power-supply-module</guid>
        <description>&lt;p&gt;I recently put together a tiny module to power my electronics projects. This is a 3cm x 4cm circuit board, and can be assembled to deliver either a fixed 3.3V or 5V output.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-01.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;927&#34;
	srcset=&#34;https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-01_hu_61623664efaf0db1.jpg 480w, https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-01_hu_8dd16e3808b56719.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;138&#34;
		data-flex-basis=&#34;331px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;background-breadboard-power-supplies&#34;&gt;Background: Breadboard power supplies
&lt;/h2&gt;&lt;p&gt;I start a lot of my projects on a breadboard, and previously used a breadboard power supply. The voltage regulators on these are not particularly resilient, and I&amp;rsquo;ve damaged two of them by wiring something up incorrectly and drawing too much current.&lt;/p&gt;
&lt;p&gt;They do not exactly &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Fail-safe&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;fail-safe&lt;/a&gt;, and now pass through the input voltage to whatever I&amp;rsquo;m working on. This is 12 V in my case, which is enough to fry most of the components I work with.&lt;/p&gt;
&lt;p&gt;A bit of searching shows that this is &lt;a class=&#34;link&#34; href=&#34;https://electronics.stackexchange.com/questions/530181/ams1117-short-circuit-protection-not-working&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;a common issue&lt;/a&gt;. The first power supply which did this was a Bud Industries BBP-32701, which uses an LM1117 regulator.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-02.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;841&#34;
	srcset=&#34;https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-02_hu_3c669f7e59170b3b.jpg 480w, https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-02_hu_dd3c3d6a11c8a4c8.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;152&#34;
		data-flex-basis=&#34;365px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The second one was a DFRobot DFR0140, which uses the AMS1117 regulator.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-03.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-03_hu_4a1d3154ec60b63e.jpg 480w, https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-03_hu_75a9222ec72175b1.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;For &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer&#34; &gt;the past year or so&lt;/a&gt;, I&amp;rsquo;ve used an L7805 regulator connected to a breadboard instead. This is not particularly efficient, but it works well, and I&amp;rsquo;ve caused enough short circuits to know that the over-current protection works.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-04.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-04_hu_2f9073dc45c13cc3.jpg 480w, https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-04_hu_8e34778141a2b7b8.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;converting-to-a-pcb&#34;&gt;Converting to a PCB
&lt;/h2&gt;&lt;p&gt;My only goal was to take the exact parts I&amp;rsquo;ve already got, and make them into a more compact module for permanent use.&lt;/p&gt;
&lt;p&gt;I used KiCad to capture the schematic and design the board. The minimum order is generally 5 circuit boards, so I planned to assemble some with an L7805 (5 V), and others with a LD33V (3.3 V) regulator. These have different pin-outs, so I added a series of solder jumpers so that I can use the same board for either regulator.&lt;/p&gt;
&lt;p&gt;&lt;div class=&#34;img-canvas-outer&#34;&gt;
&lt;a href=&#34;https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-schematic.svg&#34; class=&#34;img-canvas-link  img-xl&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-schematic.svg&#34;
	
	
	
	loading=&#34;lazy&#34;
	
	
	    class=&#34;img-canvas-inner&#34; 
	
&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Layout for this PCB was straightforward. It&amp;rsquo;s a two-layer board, and I added a ground pour on the bottom layer, and the output voltage on most of the top layer.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-05-scaled.jpg&#34;
	width=&#34;2560&#34;
	height=&#34;1417&#34;
	srcset=&#34;https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-05-scaled_hu_267ec6b7ab0453cd.jpg 480w, https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-05-scaled_hu_79c5acce57f92159.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;180&#34;
		data-flex-basis=&#34;433px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I also decided to switch off &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Thermal_relief&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;thermal relief&lt;/a&gt; on the copper pours, to see if a direct connection to a ground plane really makes soldering more difficult (it does! lesson learned).&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-06.png&#34;
	width=&#34;2684&#34;
	height=&#34;1486&#34;
	srcset=&#34;https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-06_hu_d2e0a25430ecd33e.png 480w, https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-06_hu_7f26f070ba0f2ccf.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;180&#34;
		data-flex-basis=&#34;433px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I tried to make this board quite dense, but didn&amp;rsquo;t go completely overboard: It&amp;rsquo;s useful to have holes to install standoffs, plus a small area to write on, so that I can distinguish the 5 V and 3.3 V modules later.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-07.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;902&#34;
	srcset=&#34;https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-07_hu_883846c0e2ce2723.jpg 480w, https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-07_hu_6558e58c7cba0421.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;141&#34;
		data-flex-basis=&#34;340px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap-up
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;m still a little surprised that custom PCB&amp;rsquo;s are so accessible for hobby use. The unit price of these boards was just 1.36 AUD before shipping, which is cost-competitive with blank prototyping board.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-08.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-08_hu_f452358aec97d976.jpg 480w, https://mike42.me/blog/2022-08-building-a-simple-power-supply-module/2022-08-power-board-08_hu_7afca1e9b636396f.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s easy to get assembled DC-DC converters, so I don&amp;rsquo;t suggest building any of these modules yourself. However, as with many of the things I blog about, I&amp;rsquo;ve uploaded the project files to GitHub under an open source license. The KiCad project, Gerber files and parts list for this project can be found at &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/simple-power-supply&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/simple-power-supply&lt;/a&gt;.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Let&#39;s implement power-on self test (POST)</title>
        <link>https://mike42.me/blog/2022-06-lets-implement-power-on-self-test-post</link>
        <pubDate>Thu, 16 Jun 2022 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2022-06-lets-implement-power-on-self-test-post</guid>
        <description>&lt;p&gt;I recently implemented simple &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Power-on_self-test&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Power-on self test (POST)&lt;/a&gt; routine for my &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board&#34; &gt;65C816 test board&lt;/a&gt;, so that it can stop and indicate a hardware failure before attempting to run any normal code.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-06-lets-implement-power-on-self-test-post/2022-06-65c816-post.gif&#34;
	width=&#34;350&#34;
	height=&#34;196&#34;
	
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;178&#34;
		data-flex-basis=&#34;428px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This was an interesting adventure for two main reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This code needs to work with no RAM present in the computer.&lt;/li&gt;
&lt;li&gt;I wanted to try re-purposing the emulation status (E) output on the 65C816 CPU to blink an LED.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;background&#34;&gt;Background
&lt;/h2&gt;&lt;p&gt;Even modern computers will stop and provide a blinking light or series of beeps if you don&amp;rsquo;t install RAM or a video card. This is implemented in the BIOS or UEFI.&lt;/p&gt;
&lt;p&gt;I got the idea to use the &lt;code&gt;E&lt;/code&gt; or &lt;code&gt;MX&lt;/code&gt; CPU outputs for this purpose from &lt;a class=&#34;link&#34; href=&#34;http://forum.6502.org/viewtopic.php?f=4&amp;amp;t=6932&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this thread on the 6502.org forums&lt;/a&gt;. This method would allow me to blink a light with just a CPU, clock input, and ROM working.&lt;/p&gt;
&lt;p&gt;My main goal is to perform a quick test that each device is present, so that start-up fails in a predictable way if I&amp;rsquo;ve connected something incorrectly. This is much simpler than the POST routine from a real BIOS, because I&amp;rsquo;m not doing device detection, and I&amp;rsquo;m not testing every byte of memory.&lt;/p&gt;
&lt;h2 id=&#34;boot-up-process&#34;&gt;Boot-up process
&lt;/h2&gt;&lt;p&gt;On my test board, I&amp;rsquo;ve connected an LED directly to the emulation status (&lt;code&gt;E&lt;/code&gt;) output on the 65C816 CPU. The CPU starts in emulation mode (&lt;code&gt;E&lt;/code&gt; is high). However I have noticed that on power-up, the value of &lt;code&gt;E&lt;/code&gt; appears to be random until &lt;code&gt;/RES&lt;/code&gt; goes high. If I were wiring this up again, I would also prevent the LED from lighting up while the CPU is in reset:&lt;/p&gt;
&lt;p&gt;&lt;div class=&#34;img-canvas-outer&#34;&gt;
&lt;a href=&#34;https://mike42.me/blog/2022-06-lets-implement-power-on-self-test-post/2022-06-post-circuit.svg&#34; class=&#34;img-canvas-link  img-lg&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://mike42.me/blog/2022-06-lets-implement-power-on-self-test-post/2022-06-post-circuit.svg&#34;
	
	
	
	loading=&#34;lazy&#34;
	
	
	    class=&#34;img-canvas-inner&#34; 
	
&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;The first thing the CPU does is read an address from ROM, called the reset vector, which tells it where start executing code.&lt;/p&gt;
&lt;p&gt;In my case, the first two instructions set the CPU to native mode, which are &lt;code&gt;clc&lt;/code&gt; (clear carry) and &lt;code&gt;xce&lt;/code&gt; (exchange carry with emulation).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.segment&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;CODE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;reset:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;.a8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;.i8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;clc&lt;/span&gt;                            &lt;span class=&#34;c1&#34;&gt;; switch to native mode
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;xce&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;post_check_loram&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By default accumulator and index registers are 8-bit, the &lt;code&gt;.a8&lt;/code&gt; and &lt;code&gt;.i8&lt;/code&gt; directives simply tell the assembler &lt;a class=&#34;link&#34; href=&#34;https://github.com/cc65/cc65&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;ca65&lt;/a&gt; that this is the case.&lt;/p&gt;
&lt;p&gt;Next, the code will &lt;code&gt;jmp&lt;/code&gt; to the start of the POST process.&lt;/p&gt;
&lt;h2 id=&#34;checking-low-ram&#34;&gt;Checking low RAM
&lt;/h2&gt;&lt;p&gt;The first part of the POST procedure checks if the lower part of RAM is available, by writing values to two address and checking that the same values can be read back.&lt;/p&gt;
&lt;p&gt;Note that &lt;code&gt;a:$00&lt;/code&gt; causes the assembler to interpret &lt;code&gt;$00&lt;/code&gt; as an absolute address. This will otherwise be interpreted as direct-page address, which is not what&amp;rsquo;s intended here.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;post_check_loram:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%01010101                 ; Power-on self test (POST) - do we have low RAM?
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;ldy&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%10101010
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;stx&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;$00&lt;/span&gt;                      &lt;span class=&#34;c1&#34;&gt;; store known values at two addresses
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;sty&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;$01&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;$00&lt;/span&gt;                      &lt;span class=&#34;c1&#34;&gt;; read back the values - unlikely to be correct if RAM not present
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;ldy&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;$01&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;cpx&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%01010101
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;bne&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;post_fail_loram&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;cpy&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%10101010
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;bne&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;post_fail_loram&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;post_check_hiram&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If this fails, then the boot process stops, and the emulation LED blinks in a distinctive pattern (two blinks) forever.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;post_fail_loram:&lt;/span&gt;                   &lt;span class=&#34;c1&#34;&gt;; blink emulation mode output with two pulses
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;pause&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;blink&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;blink&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;post_fail_loram&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;; repeat indefinitely
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;macros-pause-and-blink&#34;&gt;Macros: pause and blink
&lt;/h2&gt;&lt;p&gt;It&amp;rsquo;s a mini-challenge to write code to blink an LED in a distinctive pattern without assuming that RAM works. This means no stack operations (eg. &lt;code&gt;jsr&lt;/code&gt; and &lt;code&gt;rts&lt;/code&gt; instructions), and that I need to store anything I need in 3 bytes: the &lt;code&gt;A&lt;/code&gt;, &lt;code&gt;X&lt;/code&gt;, &lt;code&gt;Y&lt;/code&gt; registers. A triple-nested loop is the best I can come up with.&lt;/p&gt;
&lt;p&gt;I wrote a &lt;code&gt;pause&lt;/code&gt; macro, which runs a time-wasting loop for the requested duration - approximately a multiple of 100ms at this clock speed. Every time this macro is used, the &lt;code&gt;len&lt;/code&gt; value is substituted in, and this code is included in the source file. This example also uses unnamed labels, which is a &lt;code&gt;ca65&lt;/code&gt; feature for writing messy code.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.macro&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;pause&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;len&lt;/span&gt;                   &lt;span class=&#34;c1&#34;&gt;; time-wasting loop as macro
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#len
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#64
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;ldy&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#255
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;dey&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;cpy&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;bne&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;dex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;cpx&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;bne&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:--&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;dec&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;cmp&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;bne&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.endmacro&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The second macro I wrote is &lt;code&gt;blink&lt;/code&gt;, which briefly lights up the LED attached to the &lt;code&gt;E&lt;/code&gt; output by toggling emulation mode. I&amp;rsquo;m using the &lt;code&gt;pause&lt;/code&gt; macro from both native mode and emulation mode in this snippet, so I can only treat &lt;code&gt;A&lt;/code&gt;, &lt;code&gt;X&lt;/code&gt; and &lt;code&gt;Y&lt;/code&gt; as 8-bit registers.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.macro&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;blink&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;sec&lt;/span&gt;                            &lt;span class=&#34;c1&#34;&gt;; switch to emulation mode
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;xce&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;pause&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;clc&lt;/span&gt;                            &lt;span class=&#34;c1&#34;&gt;; switch to native mode
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;xce&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;pause&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;sec&lt;/span&gt;                            &lt;span class=&#34;c1&#34;&gt;; switch to emulation mode
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.endmacro&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;checking-high-ram&#34;&gt;Checking high RAM
&lt;/h2&gt;&lt;p&gt;There is also a second RAM chip, and this process is repeated with some differences. For one, I can now use the stack, which is how I set the data bank byte in this snippet.&lt;/p&gt;
&lt;p&gt;Here &lt;code&gt;a:$01&lt;/code&gt; is important, because with direct page addressing, &lt;code&gt;$01&lt;/code&gt; means &lt;code&gt;$000001&lt;/code&gt; at this point in the code, where I want to test that I can write to the memory address &lt;code&gt;$080001&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;post_check_hiram:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%10101010                 ; Power-on self test (POST) - do we have high RAM?
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;ldy&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%01010101
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$08                       ; data bank to high ram
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;pha&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;plb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;stx&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;$00&lt;/span&gt;                      &lt;span class=&#34;c1&#34;&gt;; store known values at two addresses
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;sty&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;$01&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;$00&lt;/span&gt;                      &lt;span class=&#34;c1&#34;&gt;; read back the values - unlikely to be correct if RAM not present
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;ldy&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;$01&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;cpx&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%10101010
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;bne&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;post_fail_hiram&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;cpy&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%01010101
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;bne&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;post_fail_hiram&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$00                       ; reset data bank to boot-up value
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;pha&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;plb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;post_check_via&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The failure here is similar, but the LED will blink 3 times instead of 2.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;post_fail_hiram:&lt;/span&gt;                   &lt;span class=&#34;c1&#34;&gt;; blink emulation mode output with three pulses. we could use RAM here?
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;pause&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;blink&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;blink&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;blink&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;post_fail_hiram&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;; repeat indefinitely
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To make sure that I was writing to different chips, I installed the RAM chips one at a time, first observing the expected failures, and then observing that the code continued past this point with the chip installed.&lt;/p&gt;
&lt;p&gt;I also checked with an oscilloscope that both RAM chips are now being accessed during start-up. Now that I&amp;rsquo;ve got some confidence that the computer now requires both chips to start, I can skip a few debugging steps if I&amp;rsquo;ve got code that isn&amp;rsquo;t working later.&lt;/p&gt;
&lt;h2 id=&#34;checking-the-versatile-interface-adapter-via&#34;&gt;Checking the Versatile Interface Adapter (VIA)
&lt;/h2&gt;&lt;p&gt;The third chip I wanted to add to the POST process is the 65C22 VIA. I kept this check simple, because one read to check for a start-up default is sufficient to test for device presence.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;VIA_IER&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$c00e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;post_check_via:&lt;/span&gt;                    &lt;span class=&#34;c1&#34;&gt;; Power-on self test (POST) - do we have a 65C22 Versatile Interface Adapter (VIA)?
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;VIA_IER&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;cmp&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%10000000                 ; start-up state, interrupts enabled overall (IFR7) but all interrupt sources (IFR0-6) disabled.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;bne&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;post_fail_via&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;post_ok&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This stops and blinks 4 times if it fails. I recorded the GIF at the top of this blog post by removing the component which generates a chip-select for the VIA, which causes this code to trigger on boot.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;post_fail_via:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;pause&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;blink&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;blink&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;blink&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;blink&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;post_fail_via&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;beep-for-good-measure&#34;&gt;Beep for good measure
&lt;/h2&gt;&lt;p&gt;At the end of the POST process, I put in some code to generate a short beep.&lt;/p&gt;
&lt;p&gt;This uses the fact that the 65C22 can toggle the &lt;code&gt;PB7&lt;/code&gt; output each time a certain number of clock-cycles pass. I&amp;rsquo;ve connected a piezo buzzer to that output, which I&amp;rsquo;m using as a PC speaker. The 65C22 is serving the role of a &lt;a class=&#34;link&#34; href=&#34;https://wiki.osdev.org/PC_Speaker&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;programmable interrupt timer&lt;/a&gt; from the PC world.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;VIA_DDRB&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$c002&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;VIA_T1C_L&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$c004&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;VIA_T1C_H&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$c005&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;VIA_ACR&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$c00b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;BEEP_FREQ_DIVIDER&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;461&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;; 1KHz, formula is CPU clock / (desired frequency * 2), or 921600 / (1000 * 2) ~= 461
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;post_ok:&lt;/span&gt;                           &lt;span class=&#34;c1&#34;&gt;; all good, emit celebratory beep, approx 1KHz for 1/10th second
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;; Start beep
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%10000000                 ; VIA PIN PB7 only
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;VIA_DDRB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%11000000                 ; set ACR. first two bits = 11 is continuous square wave output on PB7
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;VIA_ACR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#&amp;lt;BEEP_FREQ_DIVIDER        ; set T1 low-order counter
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;VIA_T1C_L&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#&amp;gt;BEEP_FREQ_DIVIDER        ; set T1 high-order counter
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;VIA_T1C_H&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;; wait approx 0.1 seconds
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;pause&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;; Stop beep
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%11000000                 ; set ACR. returns to a one-shot mode
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;VIA_ACR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;stz&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;VIA_T1C_L&lt;/span&gt;                  &lt;span class=&#34;c1&#34;&gt;; zero the counters
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;stz&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;VIA_T1C_H&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;; POST is now done
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;post_done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;post_done&lt;/code&gt; label points to the start of the old ROM code, which is currently just a &amp;ldquo;hello world&amp;rdquo; program.&lt;/p&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next steps
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;m now able to lock in some of my assumptions about should be available in software, so that I can write more complex programs without second-guessing the hardware.&lt;/p&gt;
&lt;p&gt;Once the boot ROM is interacting with more hardware, I may add additional checks. I will probably need to split this into different sections, and make use of &lt;code&gt;jsr&lt;/code&gt;/&lt;code&gt;rts&lt;/code&gt; once RAM has been tested, because the macros are currently generating a huge amount of machine code. I have 8KiB of ROM in the memory map for this computer, and the code on this page takes up around 1.1KiB.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Building a 65C816 test board</title>
        <link>https://mike42.me/blog/2022-06-building-a-65c816-test-board</link>
        <pubDate>Thu, 02 Jun 2022 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2022-06-building-a-65c816-test-board</guid>
        <description>&lt;p&gt;In the last few months, I&amp;rsquo;ve been learning about the 65C816 processor, and trying to build a working computer which uses it. My &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-05-65c816-computer-second-prototype&#34; &gt;latest breadboard-based prototype&lt;/a&gt; was not reliable, and I decided to convert it to a PCB to hopefully eliminate the problem, or to at least identify it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-assembled-board.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-assembled-board_hu_9cd2d56af1f7e67f.jpg 480w, https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-assembled-board_hu_c425d9bf33ded024.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;quick-goals&#34;&gt;Quick goals
&lt;/h2&gt;&lt;p&gt;I was aiming to make a debug-friendly 4-layer PCB, the size of two standard breadboards. This will be my first time designing a 4-layer board, and also my first time using KiCad 6 to create a PCB.&lt;/p&gt;
&lt;p&gt;I didn&amp;rsquo;t have a working prototype, so I built in test points for connecting an oscilloscope or logic analyser to troubleshoot. In case of errors, I made it possible to leave some components unpopulated, and instead drive signals externally.&lt;/p&gt;
&lt;p&gt;I also left some extra footprints which I might use for future improvements, or can fall back to if some of my ideas don&amp;rsquo;t work out.&lt;/p&gt;
&lt;h2 id=&#34;the-clock&#34;&gt;The clock
&lt;/h2&gt;&lt;p&gt;Some components require the inverse of the CPU clock, and there was previously a small delay from inverting the signal. I don&amp;rsquo;t think this is a problem on its own, but I introduced a D-type flip-flop to create a proper two-phase clock.&lt;/p&gt;
&lt;p&gt;This does halve the CPU clock speed, so I added jumpers to allow an alternative clock source to be selected for the CPU, where previously the UART and CPU clocks needed to be the same. Note that there is an error in the wiring here, which I only discovered later.&lt;/p&gt;
&lt;p&gt;&lt;div class=&#34;img-canvas-outer&#34;&gt;
&lt;a href=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-clock.svg&#34; class=&#34;img-canvas-link  img-lg&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-clock.svg&#34;
	
	
	
	loading=&#34;lazy&#34;
	
	
	    class=&#34;img-canvas-inner&#34; 
	
&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;The oscillator I&amp;rsquo;m using on the breadboard prototype is a DIP-8 package. A larger variety of oscillators are available as a 5x7mm QFN package, where the four corner pins have the same function as the DIP-8 version. I added an alternative footprint, which fits without taking up any extra board space. I expect that I&amp;rsquo;ll only use this if I attempt to run the board at 3.3V later.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-clock-layout.png&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-clock-layout_hu_6b2a5b159a808cc6.png 480w, https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-clock-layout_hu_e161e9cf5b00d347.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Some 6-pin QFN oscillators provide an inverted clock output on one of the pins, and it would be an idea to use one of those in a future design to reduce the component count.&lt;/p&gt;
&lt;h2 id=&#34;new-reset-controller&#34;&gt;New reset controller
&lt;/h2&gt;&lt;p&gt;Several components on the board require a reset input. These are mostly active-low inputs, but one component has an active-high reset. I discovered the tiny MIC2775 supervisory IC, which provides both.&lt;/p&gt;
&lt;p&gt;&lt;div class=&#34;img-canvas-outer&#34;&gt;
&lt;a href=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-reset.svg&#34; class=&#34;img-canvas-link  img-lg&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-reset.svg&#34;
	
	
	
	loading=&#34;lazy&#34;
	
	
	    class=&#34;img-canvas-inner&#34; 
	
&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;I haven&amp;rsquo;t used this part before, so in case of problems, I also made it possible to remove this part and use a DS1813, which generates an active-low reset on my prototype.&lt;/p&gt;
&lt;p&gt;&lt;div class=&#34;img-canvas-outer&#34;&gt;
&lt;a href=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-reset-alt.svg&#34; class=&#34;img-canvas-link  img-sm&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-reset-alt.svg&#34;
	
	
	
	loading=&#34;lazy&#34;
	
	
	    class=&#34;img-canvas-inner&#34; 
	
&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;These parts work by sensing voltage, and drop-in alternatives exist for either part if I move to 3.3V.&lt;/p&gt;
&lt;h2 id=&#34;rom&#34;&gt;ROM
&lt;/h2&gt;&lt;p&gt;I am currently using a parallel EEPROM to store code for my prototype, and will add this to the PCB for this test board. As with the the clock and reset controller, I&amp;rsquo;m working with 5V components today, but considering what I would need to change to run the whole board at 3.3V.&lt;/p&gt;
&lt;p&gt;The few EEPROMs which are available at 3.3V use a different package, and are quite slow (200ns or worse). Parallel flash chips seem to be the most promising alternative, since they have a similar interface, although I haven&amp;rsquo;t confirmed that I can program them yet. I added a footprint for the SST39LF010, which also has a 5V variant with the same pin-out.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-rom-layout.png&#34;
	width=&#34;2016&#34;
	height=&#34;1512&#34;
	srcset=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-rom-layout_hu_3bbc87902d42cc8b.png 480w, https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-rom-layout_hu_19b1979fd6e51640.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;other-footprints&#34;&gt;Other footprints
&lt;/h2&gt;&lt;p&gt;I also added footprints so that I could connect the SD card module which &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2012-12-assembling-my-6502-computer&#34; &gt;I used on my 6502 computer&lt;/a&gt;, a piezo buzzer, and some electrolytic capacitors if needed.&lt;/p&gt;
&lt;h2 id=&#34;design-lessons-learned&#34;&gt;Design lessons learned
&lt;/h2&gt;&lt;p&gt;Although &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb&#34; &gt;my first attempt&lt;/a&gt; at making a PCB was a success, I learned a few things which I&amp;rsquo;m using here.&lt;/p&gt;
&lt;p&gt;For that previous project, I found that machined-pin sockets are not very tolerant of used chips with bent legs, so I&amp;rsquo;ve used cheaper stamped pin sockets for this test board. I&amp;rsquo;ve also left spacing at the ends of each socketed IC, so that they can be pulled out more easily.&lt;/p&gt;
&lt;p&gt;I made an effort to keep unrelated traces away from points which I need to solder, because I had some problems with this on my last board.&lt;/p&gt;
&lt;p&gt;I also avoided creating one large expansion header, and instead exposed signals in places which are easy to route. For example, the I/O device select signals are exposed on a pin header right beside the chip which generates them.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-io-decode.png&#34;
	width=&#34;1458&#34;
	height=&#34;1093&#34;
	srcset=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-io-decode_hu_8873f7bbd0b810f9.png 480w, https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-io-decode_hu_d5a478ffc3489bc4.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;pcb-layout&#34;&gt;PCB layout
&lt;/h2&gt;&lt;p&gt;The standard process is to make a schematic, then place components, then route traces.&lt;/p&gt;
&lt;p&gt;For this test board, I instead chose the physical dimensions of the board first, and added components incrementally (particularly test points, expansion headers and alternative footprints) until I was making good use of the available space. KiCad has an item in the &amp;ldquo;Tools&amp;rdquo; menu to &amp;ldquo;Update PCB from Schematic&amp;rdquo;, which I used extensively.&lt;/p&gt;
&lt;p&gt;Just to see how it would look, I also added the letters &amp;ldquo;65C816&amp;rdquo; to the back copper layer, which is visible in the top-right here.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-full-layout.png&#34;
	width=&#34;3844&#34;
	height=&#34;2100&#34;
	srcset=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-full-layout_hu_619667c9ed3240f7.png 480w, https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-full-layout_hu_eb7aa3cda3995298.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;183&#34;
		data-flex-basis=&#34;439px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I put a lot of time into labeling different parts of the board to help with debug/assembly, and used the 3D view to check that it wasn&amp;rsquo;t too crowded.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-render-scaled.jpg&#34;
	width=&#34;2560&#34;
	height=&#34;1456&#34;
	srcset=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-render-scaled_hu_7822d9ace7f86361.jpg 480w, https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-render-scaled_hu_aebc605adb3ddc24.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;175&#34;
		data-flex-basis=&#34;421px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Before sending the files to a manufacturer, I printed it at 1:1 scale for a reality check.&lt;/p&gt;
&lt;p&gt;Among other things, this confirmed that the ROM sockets had enough clearance from other components.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-rom-print.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-rom-print_hu_b152e61a0f04c0d8.jpg 480w, https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-rom-print_hu_95c3f483a0f9e6e9.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;It also confirmed that either DIP-8 or QFN-packaged oscillators would fit.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-clock-print.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-clock-print_hu_7de2c4f6a0b27d90.jpg 480w, https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-clock-print_hu_6288836058b8c125.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;assembly&#34;&gt;Assembly
&lt;/h2&gt;&lt;p&gt;I ordered the boards from a manufacturer which I&amp;rsquo;ve used before. They are large-ish, lead-free 4-layer boards, but I&amp;rsquo;m not optimising for cost. I&amp;rsquo;ve left a lot of options in the board, so I&amp;rsquo;m hoping to make use of several of these PCBs in different configurations, depending on which direction this project goes.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-blank-boards.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-blank-boards_hu_a56e6b8c078b9ca7.jpg 480w, https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-blank-boards_hu_8056e25b3eb4d714.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I assembled the board incrementally, starting with the power LED. Most of the passive components on this board are 0603 (imperial) size surface-mount parts, and I&amp;rsquo;ve used footprints with long pads for hand soldering.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-power-led.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-power-led_hu_56d9823394445098.jpg 480w, https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-power-led_hu_a1859c41c6c86d86.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The first problem I found was with the reset button - I had switched to using a footprint with the correct pin spacing, but had assigned the pins incorrectly, so I needed to cut/bend some legs and install it rotated 90 degrees.&lt;/p&gt;
&lt;p&gt;I next found a problem with the clock, where I had wired up the flip-flop incorrectly in the schematic - the &lt;code&gt;/Q&lt;/code&gt; output should go to &lt;code&gt;D&lt;/code&gt;. I could recover from this by cutting a trace and running a short wire. Of course the board is mirrored when flipped upside-down, so I cut the wrong trace first and needed to repair that too.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-clock-fix.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-clock-fix_hu_ffc2f7b7fcef9e4e.jpg 480w, https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-clock-fix_hu_c3fc7dbd47e1e731.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I added enough components to get the CPU to run NOP instructions from ROM, then built up to a running some test programs which I&amp;rsquo;ve blogged about here. The final mistake I discovered was a mix-up with some of the lines used for selecting I/O devices, which means that devices are not mapped to their intended addresses. I can work around this in software.&lt;/p&gt;
&lt;p&gt;This is already an improvement over the breadboard prototype, because I can quickly swap the ROM chip without accidentally disconnecting anything.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-partly-assembled.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-partly-assembled_hu_e544b38f73f6962f.jpg 480w, https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-partly-assembled_hu_635c16ce9c8f8b83.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The board looked fairly complete at this point, and the only major component missing was the UART chip. This was the part which did not work reliably in my prototype, so I was prepared to do some debugging here. Note that I&amp;rsquo;ve got orange test points all over the board to connect important signals to an oscilloscope, with a few black test points for GND connections. All of the 74-series chips are in the 74AC logic family, and I sourced 74HC versions as well in case I needed to switch any to see the difference.&lt;/p&gt;
&lt;p&gt;However, I was able to run more or less &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer&#34; &gt;the same test program I used before&lt;/a&gt;, and it now works reliably. This is captured through a Cypress FX2-based logic analyser using Sigrok.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-hello.png&#34;
	width=&#34;1338&#34;
	height=&#34;779&#34;
	srcset=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-hello_hu_83959b408ebb93e9.png 480w, https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-test-hello_hu_59e03a14b1b80028.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;171&#34;
		data-flex-basis=&#34;412px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s great that this works, but I don&amp;rsquo;t know for sure why this was so unreliable on my previous prototype. Several possible causes were eliminated through this process, since I used a new UART chip and freshly programmed address decode PLD, and eliminated a possible timing issue. On a PCB, I&amp;rsquo;m also able to make better electrical connections, and add a ground plane, which is an immediate advantage over breadboards.&lt;/p&gt;
&lt;h2 id=&#34;the-design-as-it-stands&#34;&gt;The design as it stands
&lt;/h2&gt;&lt;p&gt;Now that I am back to having a working prototype, I&amp;rsquo;ll take this chance to post some updated schematics.&lt;/p&gt;
&lt;p&gt;Just a note of caution: this is snapshot of a work-in-progress learning project. I&amp;rsquo;m absolutely aware that there are errors in here, and that the layout is quite messy. Still, I hope that this is useful to anybody else who is attempting to use this relatively obscure CPU.&lt;/p&gt;
&lt;p&gt;The design no longer fits on one page, so I&amp;rsquo;ve split it into 3 sheets.&lt;/p&gt;
&lt;p&gt;&lt;div class=&#34;img-canvas-outer&#34;&gt;
&lt;a href=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-schematic-main.svg&#34; class=&#34;img-canvas-link  img-lg&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-schematic-main.svg&#34;
	
	
	
	loading=&#34;lazy&#34;
	
	
	    class=&#34;img-canvas-inner&#34; 
	
&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;h3 id=&#34;cpu&#34;&gt;CPU
&lt;/h3&gt;&lt;p&gt;The CPU sheet contains the circuitry for de-multiplexing the data bus and bank address byte. All power, reset, and clock components are in here as well, along with pin headers for the address &amp;amp; data bus, and all those test points.&lt;/p&gt;
&lt;p&gt;There are a lot of &amp;ldquo;just in case&amp;rdquo; components as well, such as pull-up resistors on the data bus, which I have not fitted.&lt;/p&gt;
&lt;p&gt;&lt;div class=&#34;img-canvas-outer&#34;&gt;
&lt;a href=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-schematic-cpu-bank-address-latching.svg&#34; class=&#34;img-canvas-link  &#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-schematic-cpu-bank-address-latching.svg&#34;
	
	
	
	loading=&#34;lazy&#34;
	
	
	    class=&#34;img-canvas-inner&#34; 
	
&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;h3 id=&#34;memory&#34;&gt;Memory
&lt;/h3&gt;&lt;p&gt;The memory section is quite straightforward. I&amp;rsquo;ve got a PLD generating chip-selects for ROM, RAM0, or RAM1, with some extra components to add some flexibility.&lt;/p&gt;
&lt;p&gt;&lt;div class=&#34;img-canvas-outer&#34;&gt;
&lt;a href=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-schematic-memory.svg&#34; class=&#34;img-canvas-link  &#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-schematic-memory.svg&#34;
	
	
	
	loading=&#34;lazy&#34;
	
	
	    class=&#34;img-canvas-inner&#34; 
	
&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;h3 id=&#34;io&#34;&gt;I/O
&lt;/h3&gt;&lt;p&gt;In case I/O is selected, there are three possible choices: the 65C22 VIA, or one of the two UART interfaces. Most of the other components on this sheet are optional footprints or external ports. Note that the clock going into the UART is mis-labelled on this sheet.&lt;/p&gt;
&lt;p&gt;&lt;div class=&#34;img-canvas-outer&#34;&gt;
&lt;a href=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-schematic-io.svg&#34; class=&#34;img-canvas-link  &#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://mike42.me/blog/2022-06-building-a-65c816-test-board/2022-06-65c816-schematic-io.svg&#34;
	
	
	
	loading=&#34;lazy&#34;
	
	
	    class=&#34;img-canvas-inner&#34; 
	
&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next steps
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;m going to spend some time using this board as a development platform for low-level software which targets the 65C816 CPU. I&amp;rsquo;ll most likely also use &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-04-building-an-emulator-for-my-65c816-computer&#34; &gt;the emulator which I put together a few weeks ago&lt;/a&gt; to speed up development, since I&amp;rsquo;ve been able to confirm that the code I&amp;rsquo;m writing works on real hardware.&lt;/p&gt;
&lt;p&gt;The basic functionality is now a lot more stable than what I had before, so this test board will allow me to prototype some different hardware options once I&amp;rsquo;ve got some simple text-based programs up and running.&lt;/p&gt;
&lt;p&gt;The hardware design, software and emulator for this computer can be found in &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/65816-computer&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;the GitHub repository for this project&lt;/a&gt;. I&amp;rsquo;m updating the repository as I make progress with this project, and the version used for this blog post is &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/65816-computer/tree/c0799e75d517b58f21213e5134d3585b044f0e6a/hardware&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;here&lt;/a&gt;.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>65C816 computer - second prototype</title>
        <link>https://mike42.me/blog/2022-05-65c816-computer-second-prototype</link>
        <pubDate>Sat, 28 May 2022 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2022-05-65c816-computer-second-prototype</guid>
        <description>&lt;p&gt;Back in February, I blogged about &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-02-65c816-computer-initial-prototype&#34; &gt;my 65816 computer prototype on breadboards&lt;/a&gt;. I recently spent some time re-building this in an attempt to add some improvements.&lt;/p&gt;
&lt;p&gt;The new prototype didn&amp;rsquo;t work particularly well, so I&amp;rsquo;ve left out quite a lot of detail from this update.&lt;/p&gt;
&lt;h2 id=&#34;power-delivery&#34;&gt;Power delivery
&lt;/h2&gt;&lt;p&gt;I soldered stranded wire to pin-headers to deliver a reliable ground and +5V power connection to each breadboard. This corrected some problems from my previous prototype, which used a long chain of unreliable connections.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-05-65c816-computer-second-prototype/2022-05-computer-prototype-01.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2022-05-65c816-computer-second-prototype/2022-05-computer-prototype-01_hu_d3c05be045f7628c.jpg 480w, https://mike42.me/blog/2022-05-65c816-computer-second-prototype/2022-05-computer-prototype-01_hu_4a99b333c76fe44.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;adding-more-ram&#34;&gt;Adding more RAM
&lt;/h2&gt;&lt;p&gt;I added a second 512 KiB RAM chip, and extended the address decoding scheme to provide a chip-select signal for it. The computer now uses the planned 20-bit address bus, though the wiring around these chips became &lt;em&gt;very&lt;/em&gt; dense.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-05-65c816-computer-second-prototype/2022-05-computer-prototype-03-scaled.jpg&#34;
	width=&#34;2560&#34;
	height=&#34;1920&#34;
	srcset=&#34;https://mike42.me/blog/2022-05-65c816-computer-second-prototype/2022-05-computer-prototype-03-scaled_hu_869a6581f54ba321.jpg 480w, https://mike42.me/blog/2022-05-65c816-computer-second-prototype/2022-05-computer-prototype-03-scaled_hu_e707d64d722635c1.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;adding-a-uart-chip&#34;&gt;Adding a UART chip
&lt;/h2&gt;&lt;p&gt;I previously &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer&#34; &gt;tested an NXP SC16C752 UART&lt;/a&gt;, and added it to this computer to provide text I/O. This is a small surface-mount chip, which I am connecting via a break-out board.&lt;/p&gt;
&lt;p&gt;My previous prototype only supported one I/O device, so I also extended the address decoding scheme with a 74AC138 decoder.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-05-65c816-computer-second-prototype/2022-05-computer-prototype-02.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2022-05-65c816-computer-second-prototype/2022-05-computer-prototype-02_hu_267bc4e29bbbc206.jpg 480w, https://mike42.me/blog/2022-05-65c816-computer-second-prototype/2022-05-computer-prototype-02_hu_64d96a8a5f139ce.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;problems&#34;&gt;Problems
&lt;/h2&gt;&lt;p&gt;I could get some simple test programs running, but text I/O did not work reliably at all. With my limited debugging tools (&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer&#34; &gt;just a logic analyser&lt;/a&gt;), I was only able to conclude that data being written by the CPU was different to what was being received by the UART.&lt;/p&gt;
&lt;p&gt;This seemed like it could be a timing or signal integrity issue, but I couldn&amp;rsquo;t be certain from looking at digital output with a low sample-rate. This image shows some control signals from when I was troubleshooting this.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-05-65c816-computer-second-prototype/2022-05-computer-prototype-05.png&#34;
	width=&#34;1920&#34;
	height=&#34;1199&#34;
	srcset=&#34;https://mike42.me/blog/2022-05-65c816-computer-second-prototype/2022-05-computer-prototype-05_hu_8578b1cc9cc3a430.png 480w, https://mike42.me/blog/2022-05-65c816-computer-second-prototype/2022-05-computer-prototype-05_hu_e303e9ddffe43c16.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;160&#34;
		data-flex-basis=&#34;384px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next steps
&lt;/h2&gt;&lt;p&gt;After hitting a dead-end, I made a list of possible causes, and decided to re-build this prototype on a debug-friendly PCB, and to source an oscilloscope for troubleshooting.&lt;/p&gt;
&lt;p&gt;More on that in my next post!&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Building an emulator for my 65C816 computer</title>
        <link>https://mike42.me/blog/2022-04-building-an-emulator-for-my-65c816-computer</link>
        <pubDate>Thu, 07 Apr 2022 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2022-04-building-an-emulator-for-my-65c816-computer</guid>
        <description>&lt;p&gt;I&amp;rsquo;ve been working on adding text-based input and output to &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-02-65c816-computer-initial-prototype&#34; &gt;my 65C816 computer prototype&lt;/a&gt;, but it&amp;rsquo;s not yet working reliably.&lt;/p&gt;
&lt;p&gt;To unblock software development, I decided to put together an emulator, so that I can test my code while the hardware is out of action.&lt;/p&gt;
&lt;h2 id=&#34;choosing-a-base-project&#34;&gt;Choosing a base project
&lt;/h2&gt;&lt;p&gt;There were three main options I considered for running 65C816 programs on a modern computer,&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Write a new emulator from scratch&lt;/li&gt;
&lt;li&gt;Extract the useful parts of an open source Super Nintendo or Apple IIgs emulator and adapt them&lt;/li&gt;
&lt;li&gt;Find a 65C816 CPU emulator, and extend it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I found a good candidate for the third option in &lt;a class=&#34;link&#34; href=&#34;https://github.com/FrancescoRigoni/Lib65816&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Lib65816&lt;/a&gt; by Francesco Rigoni, which is a C++ library for emulating a 65C816 CPU. The code is GPLv3 licensed, and I could see where I would need to make changes to match the design of my computer.&lt;/p&gt;
&lt;h2 id=&#34;process&#34;&gt;Process
&lt;/h2&gt;&lt;p&gt;After reading the code, I could see some places where I would need to modify the library, so I copied it in to a new folder, together with its &lt;a class=&#34;link&#34; href=&#34;https://github.com/FrancescoRigoni/Simple-Logger&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;logging dependency&lt;/a&gt; and &lt;a class=&#34;link&#34; href=&#34;https://github.com/FrancescoRigoni/Lib65816_Sample&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;sample program&lt;/a&gt;, and refactored it into one project.&lt;/p&gt;
&lt;p&gt;I started by extending RAM up to 16 banks (1 megabyte), and mapping in a ROM device which serves bytes from a file. I also updated the handling of interrupt vectors, so that the CPU would retrieve them from the system bus.&lt;/p&gt;
&lt;h2 id=&#34;adding-65c22-support&#34;&gt;Adding 65C22 support
&lt;/h2&gt;&lt;p&gt;My first test program was &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-03-lets-implement-preemptive-multitasking&#34; &gt;an example of preemptive multi-tasking&lt;/a&gt; from my previous blog post. At this point it ran, but did not switch between tasks, since that requires extra hardware support.&lt;/p&gt;
&lt;p&gt;I implemented a minimal support for the &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/WDC_65C22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;65C22 VIA&lt;/a&gt; used in my computer design, just enough to log changes to the outputs, and to fire interrupts from a timer.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Lib65816&lt;/code&gt; library does not support NMI interrupts, which are used in this test program. I added edge detection, and connected the interrupt output of the 65C22 to the CPU NMI input in code.&lt;/p&gt;
&lt;p&gt;This screen capture shows the test program during switching between two tasks, with a different VIA port being accessed before and after the switch.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-04-building-an-emulator-for-my-65c816-computer/2022-04-emulator-software-demo.png&#34;
	width=&#34;2170&#34;
	height=&#34;1354&#34;
	srcset=&#34;https://mike42.me/blog/2022-04-building-an-emulator-for-my-65c816-computer/2022-04-emulator-software-demo_hu_6c9c81d25f3dc979.png 480w, https://mike42.me/blog/2022-04-building-an-emulator-for-my-65c816-computer/2022-04-emulator-software-demo_hu_3c608553bc72b561.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;160&#34;
		data-flex-basis=&#34;384px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This gave me some confidence that the CPU emulation was good enough to develop on, so I moved on to the next test program.&lt;/p&gt;
&lt;h2 id=&#34;adding-serial-support&#34;&gt;Adding serial support
&lt;/h2&gt;&lt;p&gt;The second test program is also from an earlier blog post, and tests &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer&#34; &gt;printing and reading characters from an NXP SC16C752 UART&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I added a very minimal emulation of the UART chip I&amp;rsquo;m using, suppressed all of the logging, and converted output to use the &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Ncurses&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;curses&lt;/a&gt; library. This last step enabled character-by-character I/O, instead of the default line-buffered I/O.&lt;/p&gt;
&lt;p&gt;This screen capture shows the program running under emulation. It simply prints &amp;ldquo;Hello world&amp;rdquo;, then echoes back the next 3 characters that the user types.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-04-building-an-emulator-for-my-65c816-computer/2022-04-emulator-uart-demo.gif&#34;
	width=&#34;928&#34;
	height=&#34;506&#34;
	
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;183&#34;
		data-flex-basis=&#34;440px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap-up
&lt;/h2&gt;&lt;p&gt;I didn&amp;rsquo;t plan to write an emulator for my custom computer, but I am currently debugging some tricky hardware problems, and this detour will allow me to continue to make progress in other areas while I try to find a solution.&lt;/p&gt;
&lt;p&gt;I plan to keep the emulator up to date with hardware changes, since it will make it possible to demonstrate the system without any hardware access. It&amp;rsquo;s also easier to debug issues now that I can choose two different execution environments.&lt;/p&gt;
&lt;p&gt;The hardware design, software and emulator for this computer are online at &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/65816-computer&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/65816-computer&lt;/a&gt;. I would like to again acknowledge Francesco Rigoni&amp;rsquo;s work on Lib65816. I&amp;rsquo;m very grateful that he chose to release this under the GPL, since it allows me to re-use the code for my project.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Let&#39;s implement preemptive multitasking</title>
        <link>https://mike42.me/blog/2022-03-lets-implement-preemptive-multitasking</link>
        <pubDate>Thu, 10 Mar 2022 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2022-03-lets-implement-preemptive-multitasking</guid>
        <description>&lt;p&gt;I am currently working on building a computer based on the 65C816 processor. This processor has a 16-bit stack pointer, which should make it far more capable than the earlier 65C02, at least in theory.&lt;/p&gt;
&lt;p&gt;I wanted to check my understanding of how the stack works on this processor, so I tried to build the simplest possible implementation of preemptive multitasking in 65C816 assembly.&lt;/p&gt;
&lt;h2 id=&#34;what-im-working-with&#34;&gt;What I&amp;rsquo;m working with
&lt;/h2&gt;&lt;p&gt;I am working with a &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-02-65c816-computer-initial-prototype&#34; &gt;breadboard computer&lt;/a&gt;. It has no operating system, and no ability to load programs or start/stop processes.&lt;/p&gt;
&lt;p&gt;To get code running, I am assembling it on a modern computer, then writing the resulting binary to an EEPROM chip.&lt;/p&gt;
&lt;p&gt;To see the result of the code, I am using a logic analyser to watch some output pins on the 65C22 VIA. The 65C22 chip also has a timer, so I connected its interrupt output to the NMI input of the CPU for this test.&lt;/p&gt;
&lt;h2 id=&#34;test-programs&#34;&gt;Test programs
&lt;/h2&gt;&lt;p&gt;I wrote two simple programs which infinitely loop. These programs use &lt;a class=&#34;link&#34; href=&#34;https://github.com/cc65/cc65&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;ca65&lt;/a&gt; assembler syntax.&lt;/p&gt;
&lt;p&gt;The 65C22 has two 8-bit ports, so I made each test program write a recognisable pattern to its own output port, so that it&amp;rsquo;s easy to see which one is running at any given time, and check that it is not disrupted by the task switching.&lt;/p&gt;
&lt;p&gt;The first program writes to Port A of the 65C22, and alternates the value between &lt;code&gt;0000 0000&lt;/code&gt;, and &lt;code&gt;0000 0011&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.segment&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;CODE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Task 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;task_1_main:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;.a8&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; use 8-bit accumulator and index registers
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;na&#34;&gt;.i8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;sep&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%00110000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;repeat_1:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%00000000                  ; alternate between two values
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;PORTA&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%00000011
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;PORTA&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;repeat_1&lt;/span&gt;                   &lt;span class=&#34;c1&#34;&gt;; repeat forever
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The second program writes to Port B of the 65C22. This uses a &lt;code&gt;ror&lt;/code&gt; instruction to produce a pattern across all digits of the output port.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.segment&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;CODE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Task 2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;task_2_main:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;.a8&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; use 8-bit accumulator and index registers
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;na&#34;&gt;.i8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;sep&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%00110000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;clc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%01010101                  ; grab a start value
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;repeat_2:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;ror&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; rotate right
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;PORTB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;repeat_2&lt;/span&gt;                   &lt;span class=&#34;c1&#34;&gt;; repeat forever
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;context-switching&#34;&gt;Context switching
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;m implementing &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Round-robin_scheduling&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;round-robin scheduling&lt;/a&gt; between two processes.&lt;/p&gt;
&lt;p&gt;My basic plan was to use a regular interrupt routine to save context, switch the stack pointer to the other process, restore context for the next process, then return from the interrupt.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.segment&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;CODE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;nmi:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;.a16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;.i16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;rep&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%00110000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;; Save task context to stack
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;pha&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; Push A, X, Y
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;phx&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;phy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;phb&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; Push data bank, direct register
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;phd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;; swap stack pointer so that we will restore the other task
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;tsc&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; transfer current stack pointer to memory
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;temp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;next_task_sp&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;; load next stack pointer from memory
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;tcs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;temp&lt;/span&gt;                        &lt;span class=&#34;c1&#34;&gt;; previous task is up next
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;next_task_sp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;; Clear interrut
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;na&#34;&gt;.a8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;.i8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;sep&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%00110000                  ; save X only (assumes it is 8 bits..)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;T1C_L&lt;/span&gt;                       &lt;span class=&#34;c1&#34;&gt;; Clear the interrupt, side-effect of reading
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;.a16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;.i16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;rep&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%00110000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;; Restore process context from stack, reverse order
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;pld&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; Pull direct register, data bank
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;plb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;ply&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; Pull Y, X, A
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;plx&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;pla&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;rti&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;setup-process&#34;&gt;Setup process
&lt;/h2&gt;&lt;p&gt;The above switch works while the two processes are up and running, that takes some setting up. Firstly, the two variables need to be referenced somewhere.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.segment&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;BSS&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;next_task_sp:&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;.res&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;              &lt;span class=&#34;c1&#34;&gt;; Stack pointer of whichever task is not currently running
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;temp:&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;.res&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The boot-up routine then sets everything up. It&amp;rsquo;s broken up a bit here. First is the CPU initialisation, since the 65C816 will boot to emulation mode.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.segment&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;CODE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;reset:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;clc&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; switch to native mode
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;xce&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The second step is to start a task in the background. This involves pushing appropriate values to the stack, so that when we context switch, &amp;ldquo;Task 2&amp;rdquo; will start executing from the top.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;; Save context as if we are at task_2_main, so we can switch to it later.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;na&#34;&gt;.a16&lt;/span&gt;                            &lt;span class=&#34;c1&#34;&gt;; use 16-bit accumulator and index registers
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;na&#34;&gt;.i16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;rep&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%00110000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$3000                      ; set up stack, direct page at $3000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;tcs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;tcd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;; emulate what is pushed to the stack before NMI is called: program bank, program counter, processor status register
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;phk&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; program bank register, same as current code, will be 0 here.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;pea&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;task_2_main&lt;/span&gt;                 &lt;span class=&#34;c1&#34;&gt;; 16 bit program counter for the start of this task
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;php&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; processor status register
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;; match what we push to the stack in the nmi routine
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;tax&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;tay&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;pha&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; Push A, X, Y
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;phx&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;phy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;phb&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; Push data bank, direct register
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;phd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;tsc&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; save stack pointer to next_task_sp
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;next_task_sp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$2000                      ; set up stack, direct page at $2000 for task_1_main
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;tcs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;tcd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The nex step is to set up a timer, so that the interrupt routine will fire regularly. This causes interrupts to occur ~28 times per second.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;; Set up the interrupt timer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;na&#34;&gt;.a8&lt;/span&gt;                             &lt;span class=&#34;c1&#34;&gt;; use 8-bit accumulator and index registers
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;na&#34;&gt;.i8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;sep&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%00110000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%11111111                  ; set all VIA pins to output
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;DDRA&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;DDRB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;; set up timer 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%01000000                  ; set ACR. first two bits = 01 is continuous interrupts for T1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ACR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%11000000                  ; enable VIA interrupt for T1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;IER&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;; set up a timer at ~65535 clock pulses.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$ff                        ; set T1 low-order counter
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;T1C_L&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$ff                        ; set T1 high-order counter
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;T1C_H&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, &amp;ldquo;Task 1&amp;rdquo; can be started in the foreground.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;; start running task 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;task_1_main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;linker-configuration-and-boilerplate&#34;&gt;Linker configuration and boilerplate
&lt;/h2&gt;&lt;p&gt;This is the first time I&amp;rsquo;m blogging about code written in 65C816 native mode, so for the sake of completeness, I&amp;rsquo;ll also include the updated linker configuration. The most important change (&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-02-65c816-computer-initial-prototype&#34; &gt;compared with this blog post&lt;/a&gt;) to that 32 bytes are now set aside for interrupt vectors.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;MEMORY {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ZP:     start = $00,    size = $0100, type = rw, file = &amp;#34;&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    RAM:    start = $0100,  size = $7e00, type = rw, file = &amp;#34;&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    PRG:    start = $e000,  size = $2000, type = ro, file = %O, fill = yes, fillval = $00;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SEGMENTS {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ZEROPAGE: load = ZP,  type = zp;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    BSS:      load = RAM, type = bss;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    CODE:     load = PRG, type = ro,  start = $e000;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    VECTORS:  load = PRG, type = ro,  start = $ffe0;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that this linker configuration is not quite complete, but it is good enough to get code running. The zero page is not relevant for the code I&amp;rsquo;ll be writing, so I might remove that at some point.&lt;/p&gt;
&lt;p&gt;I also have definitions for the 65C22 I/O registers, which correspond to the location that it is mapped into RAM on my prototype computer.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;PORTB&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$c000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;PORTA&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$c001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;DDRB&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$c002&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;DDRA&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$c003&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;T1C_L&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$c004&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;T1C_H&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$c005&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;ACR&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$c00b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;IFR&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$c00b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;IER&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$c00e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The final piece of the puzzle then, are definitions for all those interrupt vectors.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.segment&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;CODE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;irq:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;rti&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;unused_interrupt:&lt;/span&gt;                 &lt;span class=&#34;c1&#34;&gt;; Probably make this into a crash.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;rti&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.segment&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;VECTORS&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; native mode interrupt vectors
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;unused_interrupt&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;; Reserved
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;unused_interrupt&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;; Reserved
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;unused_interrupt&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;; COP
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;unused_interrupt&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;; BRK
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;unused_interrupt&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;; Abort
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nmi&lt;/span&gt;                         &lt;span class=&#34;c1&#34;&gt;; NMI
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;unused_interrupt&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;; Reserved
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;irq&lt;/span&gt;                         &lt;span class=&#34;c1&#34;&gt;; IRQ
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; emulation mode interrupt vectors
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;unused_interrupt&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;; Reserved
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;unused_interrupt&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;; Reserved
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;unused_interrupt&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;; COP
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;unused_interrupt&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;; Reserved
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;unused_interrupt&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;; Abort
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;unused_interrupt&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;; NMI
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;reset&lt;/span&gt;                       &lt;span class=&#34;c1&#34;&gt;; Reset
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;unused_interrupt&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;; IRQ/BRK
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The process for building this assembly code into a usable ROM are:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ca65 --cpu 65816 main.s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ld65 -o rom.bin -C system.cfg main.o
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This outputs an 8KiB file. I need to pad this with zeroes up to 32KiB, which is the size of the ROM chip I am burning it to.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;truncate -s 32768 rom.bin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Lastly, I write this to the ROM.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;minipro -p AT28C256 -w rom.bin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;result&#34;&gt;Result
&lt;/h2&gt;&lt;p&gt;I connected a logic analyser to two wires from each output port, the &lt;code&gt;NMI&lt;/code&gt; interrupt line, and the reset signal, and opened up &lt;code&gt;sigrok&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This clearly shows the CPU switching between the two processes each time an interrupt is triggered.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-03-lets-implement-preemptive-multitasking/2022-03-multitasking-01.png&#34;
	width=&#34;1615&#34;
	height=&#34;952&#34;
	srcset=&#34;https://mike42.me/blog/2022-03-lets-implement-preemptive-multitasking/2022-03-multitasking-01_hu_6033c800cf166b7f.png 480w, https://mike42.me/blog/2022-03-lets-implement-preemptive-multitasking/2022-03-multitasking-01_hu_4196ceee83d0daa2.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;169&#34;
		data-flex-basis=&#34;407px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Zooming in on the task cut-over, I can also see that the patterns on each port are different, as expected.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-03-lets-implement-preemptive-multitasking/2022-03-multitasking-02.png&#34;
	width=&#34;1615&#34;
	height=&#34;952&#34;
	srcset=&#34;https://mike42.me/blog/2022-03-lets-implement-preemptive-multitasking/2022-03-multitasking-02_hu_b2b1a438a63c5793.png 480w, https://mike42.me/blog/2022-03-lets-implement-preemptive-multitasking/2022-03-multitasking-02_hu_6b28a1119315bf4f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;169&#34;
		data-flex-basis=&#34;407px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Of course this did not work the first time, and I spent quite a bit of time de-constructing and re-constructing the code to isolate bugs.&lt;/p&gt;
&lt;p&gt;As result, I shipped some improvements to my &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/6502-assembly-intellij&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;6502 assembly plugin&lt;/a&gt; for JetBrains IDE&amp;rsquo;s, which I have &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-05-intellij-plugin-for-6502-assembly-language&#34; &gt;blogged about previously&lt;/a&gt;. The plugin will now provide suggestions for mnemonics. There is a project setting for 6502 vs 65C02 vs 65C816 mode, and it will only suggest mnemonics which are available for the CPU.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-03-lets-implement-preemptive-multitasking/2022-03-plugin-improvement-01.png&#34;
	width=&#34;698&#34;
	height=&#34;256&#34;
	srcset=&#34;https://mike42.me/blog/2022-03-lets-implement-preemptive-multitasking/2022-03-plugin-improvement-01_hu_2e287d4de8231edd.png 480w, https://mike42.me/blog/2022-03-lets-implement-preemptive-multitasking/2022-03-plugin-improvement-01_hu_57ae7cda46bbfd2c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;272&#34;
		data-flex-basis=&#34;654px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;It also provides a weak warning for binary or hex numbers which are not 8, 16 or 24 bits, which &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/65816-computer/commit/8737aeaa854788a4fed921a288025934bd89abf9&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;would have saved me some time&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-03-lets-implement-preemptive-multitasking/2022-03-plugin-improvement-02.png&#34;
	width=&#34;506&#34;
	height=&#34;136&#34;
	srcset=&#34;https://mike42.me/blog/2022-03-lets-implement-preemptive-multitasking/2022-03-plugin-improvement-02_hu_c862059a3886ee72.png 480w, https://mike42.me/blog/2022-03-lets-implement-preemptive-multitasking/2022-03-plugin-improvement-02_hu_41ded97476b92510.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;372&#34;
		data-flex-basis=&#34;892px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Lastly, it has optional checking for undefined/unused values. This helps catch problems in the editor, and allows me to identify unused code and variables.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-03-lets-implement-preemptive-multitasking/2022-03-plugin-improvement-03.png&#34;
	width=&#34;426&#34;
	height=&#34;120&#34;
	srcset=&#34;https://mike42.me/blog/2022-03-lets-implement-preemptive-multitasking/2022-03-plugin-improvement-03_hu_24b949beade8a7e8.png 480w, https://mike42.me/blog/2022-03-lets-implement-preemptive-multitasking/2022-03-plugin-improvement-03_hu_ed4645fde8b7f7e3.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;355&#34;
		data-flex-basis=&#34;852px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap-up
&lt;/h2&gt;&lt;p&gt;I already knew how multitasking works on a high-level, but it was quite interesting to implement it myself. I have been using this as a test program for my 65C816 computer, since it exercises RAM, ROM, I/O, and uses interrupts.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t think I will be able to use this exact method for more complex programs, because it will break down a bit with multiple interrupt sources. After writing this code, I also found that it&amp;rsquo;s not common for modern systems to save register values to the stack when context-switching, and that a &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Process_control_block&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;process control block&lt;/a&gt; is used instead.&lt;/p&gt;
&lt;p&gt;The next step for my 65C816 computer will be the addition of an NXP UART, which I &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer&#34; &gt;tested in an earlier blog post&lt;/a&gt;.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Interfacing an NXP UART to an 8-bit computer</title>
        <link>https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer</link>
        <pubDate>Thu, 24 Feb 2022 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer</guid>
        <description>&lt;p&gt;I recently tested the SC16C752 UART from NXP with my 6502 computer, and I was able to use it to receive and send characters. This blog post shows the simple test program and circuit that I used.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer/2022-02-6502-nxp-uart-01.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer/2022-02-6502-nxp-uart-01_hu_1456ac80102003b3.jpg 480w, https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer/2022-02-6502-nxp-uart-01_hu_86cc3ec256e553f7.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;some-background&#34;&gt;Some background
&lt;/h2&gt;&lt;p&gt;I built a &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/6502-computer&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;65C02-based&lt;/a&gt; computer last year, which uses a serial connection for text I/O. I &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer&#34; &gt;used the WDC 65C51N&lt;/a&gt; to provide a UART interface, and I found it to be quite limited.&lt;/p&gt;
&lt;p&gt;I am now &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-01-a-first-look-at-the-65c816-processor&#34; &gt;building a 16-bit computer&lt;/a&gt;, and I want to avoid the 65C51N, for two main reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It runs at 5v, and I&amp;rsquo;m planning to convert the design to 3.3v later on. The other 65-series chips I&amp;rsquo;m using support a wide voltage range.&lt;/li&gt;
&lt;li&gt;It can only store one byte at a time. I am planning to run at a higher baud rate, and the system will have &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-11-building-a-hardware-interrupt-controller&#34; &gt;multiple interrupt sources&lt;/a&gt;. It would take very careful programming to avoid losing bytes with a 65C51N in this setup.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I spent some time investigating alternative UART IC&amp;rsquo;s, and found &lt;a class=&#34;link&#34; href=&#34;http://forum.6502.org/viewtopic.php?f=4&amp;amp;t=4178&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;some discussion on 6502.org&lt;/a&gt; about replacing the 6551 with an NXP industrial (SC26 or SC28 series) UART. At the time of writing, many of the hobbyist-friendly PLCC versions of these chips are listed as end of life, though I&amp;rsquo;ve since found pin and software-compatible versions of this made by MaxLinear (eg. the XR88C92).&lt;/p&gt;
&lt;p&gt;For my uses though, I chose the NXP SC16C752. It has two channels, 64-byte receive and transmit buffers, and supports a wide voltage range. I don&amp;rsquo;t mind that it&amp;rsquo;s a different series to these standard chips, because I plan to write software from scratch. The only downside is the packaging, which is LQFP48 with 0.5mm pin pitch. I needed to solder this tiny chip to an adapter board in order to use it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer/2022-02-6502-nxp-uart-02.jpg&#34;
	width=&#34;1416&#34;
	height=&#34;1062&#34;
	srcset=&#34;https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer/2022-02-6502-nxp-uart-02_hu_a504b8e4a49b432e.jpg 480w, https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer/2022-02-6502-nxp-uart-02_hu_80170496fef564ff.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;the-test-circuit&#34;&gt;The test circuit
&lt;/h2&gt;&lt;p&gt;I wired this up to my 6502 computer project as shown in the diagram below. &lt;code&gt;IO3&lt;/code&gt; is a spare address decoding output, which maps the chip to address &lt;code&gt;$8c00&lt;/code&gt;, while the rest of the signals connect to the 6502 CPU directly.&lt;/p&gt;
&lt;p&gt;&lt;div class=&#34;img-canvas-outer&#34;&gt;
&lt;a href=&#34;https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer/2022-02-6502-nxp-uart.svg&#34; class=&#34;img-canvas-link  &#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer/2022-02-6502-nxp-uart.svg&#34;
	
	
	
	loading=&#34;lazy&#34;
	
	
	    class=&#34;img-canvas-inner&#34; 
	
&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;I used a 74AC00 and 74AC04 to generate the active-high reset and separate read/write signals (as suggested on &lt;a class=&#34;link&#34; href=&#34;http://forum.6502.org/viewtopic.php?f=4&amp;amp;t=4178&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;the same thread linked before&lt;/a&gt;). I plan to use a PLD to generate a qualified write signals on my 65C816 computer build.&lt;/p&gt;
&lt;p&gt;Note that there are separate chip-selects for each UART, and I&amp;rsquo;ve only connected one here. I have also not connected the interrupt output for this test, and have some unused inputs which are left floating.&lt;/p&gt;
&lt;h2 id=&#34;developing-a-test-program&#34;&gt;Developing a test program
&lt;/h2&gt;&lt;p&gt;I started writing some code, and connected a logic analyser to the UART output. The early tests did not work well, and I now know that this is because I had not enabled the FIFOs, causing characters to be lost.&lt;/p&gt;
&lt;p&gt;This screen capture shows an attempt to send the entire alphabet to the UART, but only the letters &amp;ldquo;A&amp;rdquo;, &amp;ldquo;B&amp;rdquo; and &amp;ldquo;M&amp;rdquo; appearing at the output.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer/2022-02-6502-nxp-uart-03.png&#34;
	width=&#34;3510&#34;
	height=&#34;1420&#34;
	srcset=&#34;https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer/2022-02-6502-nxp-uart-03_hu_97494c745c29e28e.png 480w, https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer/2022-02-6502-nxp-uart-03_hu_8da544d00474b22f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;247&#34;
		data-flex-basis=&#34;593px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I came up with this test program, which does &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/8-N-1&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;8-N-1&lt;/a&gt; communication at 115,200 bits per second.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Test program for the SC16C752B dual UART from NXP
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.import&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;sys_exit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Assuming /CSA is connected to IO3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;UART_BASE&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$8c00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; UART registers
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Not included: FIFO ready register, Xon1 Xon2 words.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;UART_RHR&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_BASE&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;; Receiver Holding Register (RHR) - R
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;UART_THR&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_BASE&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;; Transmit Holding Register (THR) - W
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;UART_IER&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_BASE&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;; Interrupt Enable Register (IER) - R/W
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;UART_IIR&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_BASE&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;; Interrupt Identification Register (IIR) - R
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;UART_FCR&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_BASE&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;; FIFO Control Register (FCR) - W
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;UART_LCR&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_BASE&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;; Line Control Register (LCR) - R/W
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;UART_MCR&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_BASE&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;; Modem Control Register (MCR) - R/W
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;UART_LSR&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_BASE&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;; Line Status Register (LSR) - R
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;UART_MSR&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_BASE&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;; Modem Status Register (MSR) - R
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;UART_SPR&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_BASE&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;; Scratchpad Register (SPR) - R/W
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Different meaning when LCR is logic 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;UART_DLL&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_BASE&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;; Divisor latch LSB - R/W
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;UART_DLM&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_BASE&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;; Divisor latch MSB - R/W
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Different meaning when LCR is %1011 1111 ($bh).
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;UART_EFR&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_BASE&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;; Enhanced Feature Register (EFR) - R/W
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;UART_TCR&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_BASE&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;; Transmission Control Register (TCR) - R/W
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;UART_TLR&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_BASE&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;; Trigger Level Register (TLR) - R/W
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.segment&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;CODE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;main:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$80                  ; Enable divisor latches
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_LCR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#1                    ; Set divisior to 1 - on a 1.8432 MHZ XTAL1, this gets 115200bps.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_DLL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_DLM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%00010111            ; Sets up 8-n-1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_LCR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%00001111            ; Enable FIFO, set DMA mode 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_FCR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;test_print&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;test_recv&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;sys_exit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;test_print:&lt;/span&gt;                 &lt;span class=&#34;c1&#34;&gt;; Send test string to UART
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;test_char:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;test_string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;X&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;beq&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;test_done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_THR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;inx&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;test_char&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;test_done:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;rts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;test_string:&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;.asciiz&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Hello, world!&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;test_recv:&lt;/span&gt;                  &lt;span class=&#34;c1&#34;&gt;; Receive three characters and echo them back
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;uart_recv_char&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_THR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;uart_recv_char&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_THR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;uart_recv_char&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_THR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;rts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;uart_recv_char:&lt;/span&gt;             &lt;span class=&#34;c1&#34;&gt;; Receive next char to A register
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_LSR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%00000001
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;cmp&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%00000001
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;bne&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;uart_recv_char&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;UART_RHR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;rts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The program sends the text &amp;ldquo;Hello, world!&amp;rdquo;, then waits for input. The next three characters it receives are sent back to the user, and then the program terminates. The only thing in this test program which is specific to my 6502 computer is &lt;code&gt;sys_exit&lt;/code&gt;, which a routine to transfer control back to the operating system.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer/2022-02-6502-nxp-uart-04.png&#34;
	width=&#34;1576&#34;
	height=&#34;1066&#34;
	srcset=&#34;https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer/2022-02-6502-nxp-uart-04_hu_aecc5fe437fe1673.png 480w, https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer/2022-02-6502-nxp-uart-04_hu_4c52b8e62189f8ca.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;147&#34;
		data-flex-basis=&#34;354px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;It was very rewarding to see the fast, error-free text output on the logic analyser for the first time. This is a great improvement from the 65C51N.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer/2022-02-6502-nxp-uart-05.png&#34;
	width=&#34;1767&#34;
	height=&#34;1042&#34;
	srcset=&#34;https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer/2022-02-6502-nxp-uart-05_hu_e78e0fae65e6586d.png 480w, https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer/2022-02-6502-nxp-uart-05_hu_a7e0ed710de281d2.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;169&#34;
		data-flex-basis=&#34;406px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I was also surprised at how short the delay is to echo back a character. It will be interesting to see how much the latency increases once there is some more complex software handling the input.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer/2022-02-6502-nxp-uart-06.png&#34;
	width=&#34;1767&#34;
	height=&#34;1298&#34;
	srcset=&#34;https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer/2022-02-6502-nxp-uart-06_hu_8194ae6d75d0c4b0.png 480w, https://mike42.me/blog/2022-02-interfacing-an-nxp-uart-to-an-8-bit-computer/2022-02-6502-nxp-uart-06_hu_1655d9750b33b1c4.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;136&#34;
		data-flex-basis=&#34;326px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;wrap-up-and-next-steps&#34;&gt;Wrap up and next steps
&lt;/h2&gt;&lt;p&gt;I plan to use the NXP SC16C752 for my 65C816 computer project, which will be controlled via text-based input and output.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m testing it on its own first, so that I can refer to a known-good setup if it doesn&amp;rsquo;t work. This is enough to get started, though there are some features which I wasn&amp;rsquo;t able to test yet, since I can&amp;rsquo;t use custom interrupt service routines on this setup.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>65C816 computer - initial prototype</title>
        <link>https://mike42.me/blog/2022-02-65c816-computer-initial-prototype</link>
        <pubDate>Thu, 10 Feb 2022 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2022-02-65c816-computer-initial-prototype</guid>
        <description>&lt;p&gt;I am currently working on building a 65C816-based computer from scratch. I have some ideas for how I want to do this, but my first task is to put together a working prototype. I&amp;rsquo;ll be extending this in different ways to work towards the &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2022-01-a-first-look-at-the-65c816-processor&#34; &gt;goals outlined in my last blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is about the simplest computer I can come up with which uses the 65C816 processor, but there is still quite a lot to go though.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-02-65c816-computer-initial-prototype/2022-02-65c816-prototype-breadboard.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2022-02-65c816-computer-initial-prototype/2022-02-65c816-prototype-breadboard_hu_a89b2c9e1570cf1b.jpg 480w, https://mike42.me/blog/2022-02-65c816-computer-initial-prototype/2022-02-65c816-prototype-breadboard_hu_6f83fd81ed1b2928.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;parts&#34;&gt;Parts
&lt;/h2&gt;&lt;p&gt;All of the integrated circuits on this prototype are through-hole packages, suitable for use on a breadboard.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;WDC W65C816S CPU&lt;/li&gt;
&lt;li&gt;WDC W65C22S VIA I/O chip.&lt;/li&gt;
&lt;li&gt;Alliance AS6C4008-55PCN 512k x 8 55ns SRAM&lt;/li&gt;
&lt;li&gt;Atmel AT28C256 32k x 8 EEPROM&lt;/li&gt;
&lt;li&gt;Atmel ATF22LV10 PLD for address decoding&lt;/li&gt;
&lt;li&gt;74AC04, 74AC245, 74AC573 for handling the multiplexed data bus and bank address bits&lt;/li&gt;
&lt;li&gt;1.8432 MHz oscillator&lt;/li&gt;
&lt;li&gt;DS1813-5+ supervisory circuit&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also used the following equipment to program the chips, and view the result of the test program:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TL-866II+ EEPROM programmer&lt;/li&gt;
&lt;li&gt;8-channel Cypress FX2-based logic analyser&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;m working on Linux, and also use the following software tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://cc65.github.io/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;ca65&lt;/a&gt; - for assembling code for the CPU&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://gitlab.com/DavidGriffith/minipro&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;minipro&lt;/a&gt; - for programming the EEPROM and PLD.&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/simon-frankau/galette&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;galette&lt;/a&gt; - for assembling the logic definitions for the PLD.&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://sigrok.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;sigrok&lt;/a&gt; - for working with the logic analyser&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;bank-address-latching&#34;&gt;Bank address latching
&lt;/h2&gt;&lt;p&gt;The 65C816 has a 24-bit address bus, and the top 8 bits are multiplexed onto the data bus. This is not a big problem, but it does mean that I need some extra glue logic compared to a plain 6502 system. A diagram in the 65C816 data sheet shows a suggestion for how to do this, and I&amp;rsquo;m starting with that implementation.&lt;/p&gt;
&lt;p&gt;I used a 74AC04 to invert the clock, 74AC245 bus transceiver for the data bus, and a 74AC573 latch for the bank address (upper 8 bits of the address bus). This first page also shows the DS1813-5+ supervisory circuit on the reset line, which resets all of the components on power-up.&lt;/p&gt;
&lt;p&gt;&lt;div class=&#34;img-canvas-outer&#34;&gt;
&lt;a href=&#34;https://mike42.me/blog/2022-02-65c816-computer-initial-prototype/2022-02-65c816-bank-address-schematic.svg&#34; class=&#34;img-canvas-link  &#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://mike42.me/blog/2022-02-65c816-computer-initial-prototype/2022-02-65c816-bank-address-schematic.svg&#34;
	
	
	
	loading=&#34;lazy&#34;
	
	
	    class=&#34;img-canvas-inner&#34; 
	
&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m aware that I should be generating a &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Clock_signal#Two-phase_clock&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;two-phase clock&lt;/a&gt; (there is some discussion about that &lt;a class=&#34;link&#34; href=&#34;http://forum.6502.org/viewtopic.php?f=4&amp;amp;t=3404&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;here&lt;/a&gt;), though I can&amp;rsquo;t see any problems arising from the the delay on the inverted clock on this particular circuit.&lt;/p&gt;
&lt;h2 id=&#34;memory-map-and-address-decoding&#34;&gt;Memory map and address decoding
&lt;/h2&gt;&lt;p&gt;The memory map for this computer is very simple. All of this will change, but I did need to start with something to get some code running.&lt;/p&gt;
&lt;p&gt;Only the lower 19 bits of the address space are properly decoded, and mapped to one of three chips.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Address&lt;/th&gt;
          &lt;th&gt;Maps to&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;010000 - 07FFFF&lt;/td&gt;
          &lt;td&gt;RAM - 448 KiB&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;00E000 - 00FFFF&lt;/td&gt;
          &lt;td&gt;ROM - 8 KiB&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;00C000 - 00DFFF&lt;/td&gt;
          &lt;td&gt;I/O - 8 KiB&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;000000 - 00BFFF&lt;/td&gt;
          &lt;td&gt;RAM - 48 KiB&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;I used a programmable logic device (PLD) to implement this. It&amp;rsquo;s easy enough to do this with discrete gates, but a PLD will make it much easier to keep chip count and propagation delays under control as I add more features. I&amp;rsquo;ve written about programming PLD&amp;rsquo;s in previous blog posts (&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic&#34; &gt;here&lt;/a&gt;, &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-10-programming-plds-with-open-source-software&#34; &gt;here&lt;/a&gt; and &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-11-building-a-hardware-interrupt-controller&#34; &gt;here&lt;/a&gt;), and I plan to use them to implement several features.&lt;/p&gt;
&lt;p&gt;The particular part I am programming here is an ATF22LV10. These are still produced the time of writing, and operate at either 3.3 volts or 5 volts, which is useful for this project. They can be also programmed with the common TL-866II+ chip programmer, which I also use for programming EEPROMs.&lt;/p&gt;
&lt;p&gt;The definitions for decoding this are below. I called this file &lt;code&gt;address_decode.pld&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;GAL22V10
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AddrDecode
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Clock  RW     NC     NC     A19    A18    A17    A16    A15    A14    A13    GND
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;NC     /RAMCS /ROMCS /IOCS  /RD    /WR    NC     NC     NC     NC     NC     VCC
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; ROM is the top 8 KiB of bank 0.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; prefix is 0000 111xxxxx xxxxxxxx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ROMCS = /A19*/A18*/A17*/A16*A15*A14*A13
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; IO addresses are mapped below ROM in bank 0.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; prefix is 0000 110xxxxx xxxxxxxx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IOCS = /A19*/A18*/A17*/A16*A15*A14*/A13
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; RAM is selected for any address does *not* match 0000 11xxxxxx xxxxxxxx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;RAMCS = A19 + A18 + A17 + A16 + /A15 + /A14
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; Qualify writes with clock
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;RD = RW
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;WR = Clock*/RW
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;DESCRIPTION
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Address decode logic for 65C816 computer.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ROM is top 8K of bank 0, I/O is 8k below that, everything else is RAM.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I assembled this with galette:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;galette address_decode.pld
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This generates a &lt;code&gt;.jed&lt;/code&gt; file, which can be used to program the chip. The ATF22LV10 is not on the compatibility list for my programmer, but it works just fine if I identify it as an ATF22V10CQZ.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;minipro -p ATF22V10CQZ -w address_decode.jed
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;div class=&#34;img-canvas-outer&#34;&gt;
&lt;a href=&#34;https://mike42.me/blog/2022-02-65c816-computer-initial-prototype/2022-02-65c816-memory-io.svg&#34; class=&#34;img-canvas-link  &#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://mike42.me/blog/2022-02-65c816-computer-initial-prototype/2022-02-65c816-memory-io.svg&#34;
	
	
	
	loading=&#34;lazy&#34;
	
	
	    class=&#34;img-canvas-inner&#34; 
	
&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;h2 id=&#34;firmware-and-testing&#34;&gt;Firmware and testing
&lt;/h2&gt;&lt;p&gt;I came up with a simple test program which would require working ROM, RAM, and I/O. The CPU boots to 6502 emulation mode, and this test program does not access memory outside bank 0.&lt;/p&gt;
&lt;p&gt;I created a linker configuration file which mostly reflects the system&amp;rsquo;s memory map, and called it &lt;code&gt;system.cfg&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;MEMORY {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ZP:     start = $00,    size = $0100, type = rw, file = &amp;amp;quot;&amp;amp;quot;;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    RAM:    start = $0100,  size = $7e00, type = rw, file = &amp;amp;quot;&amp;amp;quot;;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    PRG:    start = $e000,  size = $2000, type = ro, file = %O, fill = yes, fillval = $00;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SEGMENTS {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ZEROPAGE: load = ZP,  type = zp;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    BSS:      load = RAM, type = bss;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    CODE:     load = PRG, type = ro,  start = $e000;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    VECTORS:  load = PRG, type = ro,  start = $fffa;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I then wrote this test program, &lt;code&gt;main.s&lt;/code&gt;. The program runs from ROM, and writes a hard-coded value to one of the output ports. It then stores a 0 in RAM, then increments it and stores that to an output port in an infinite loop, which will show a counting pattern if RAM can be read and written.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;PORTB&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$c000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;DDRB&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$c002&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;SOME_ADDRESS_IN_RAM&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$beef&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.segment&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;quot&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;;CODE&amp;amp;quot;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Write 42 to VIA port B
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;reset:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%11111111 ; Set all pins to output
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;DDRB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#42
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;PORTB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Start at 0, and increment a value in RAM
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#00
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;SOME_ADDRESS_IN_RAM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;loop:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;inc&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;SOME_ADDRESS_IN_RAM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;SOME_ADDRESS_IN_RAM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;PORTB&lt;/span&gt;			&lt;span class=&#34;c1&#34;&gt;; Output the value
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;loop&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;nmi:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;rti&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;irq:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;rti&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.segment&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;quot&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;;VECTORS&amp;amp;quot;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nmi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;reset&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;irq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I assembled this with &lt;code&gt;ca65&lt;/code&gt;, then linked it with &lt;code&gt;ld65&lt;/code&gt;. As far as the assembler knows, it is generating code for a 6502 CPU, not a 65C816. I am not using any advanced features, so this should be fine for this test.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ca65 main.s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ld65 -o rom.bin -C system.cfg main.o
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This outputs an 8 KiB binary file, which is the amount of ROM space mapped in the computer&amp;rsquo;s memory. The chip is actually 32 KiB though, so I filled the rest with zeroes.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;truncate -s 32768 rom.bin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I then wrote the program to the EEPROM using minipro.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;minipro -p AT28C256 -w rom.bin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I ran this program, with a logic analyser connected to port B of the 65C22 VIA. The capture below shows the initial hard-coded number, followed by the counting pattern, which indicates that everything is working as expected.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-02-65c816-computer-initial-prototype/2022-02-65c816-port-b-incrementing.png&#34;
	width=&#34;2860&#34;
	height=&#34;1463&#34;
	srcset=&#34;https://mike42.me/blog/2022-02-65c816-computer-initial-prototype/2022-02-65c816-port-b-incrementing_hu_40d3e4510f0f7eaf.png 480w, https://mike42.me/blog/2022-02-65c816-computer-initial-prototype/2022-02-65c816-port-b-incrementing_hu_ee4e7a6621b6330d.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;195&#34;
		data-flex-basis=&#34;469px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap-up
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;m starting simple here, so that I have a working base system to modify. Everything seems to be working fine on breadboards, so I&amp;rsquo;ll proceed with that for now. I may still need to re-build everything with shorter wires, since this is getting quite difficult to work with.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-02-65c816-computer-initial-prototype/2022-02-65c816-prototype-breadboard-2.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2022-02-65c816-computer-initial-prototype/2022-02-65c816-prototype-breadboard-2_hu_970e8ed0a1c72092.jpg 480w, https://mike42.me/blog/2022-02-65c816-computer-initial-prototype/2022-02-65c816-prototype-breadboard-2_hu_b51acf6f2940302e.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;It is also worth noting that most of the components here should run at 3.3 volts, which is where this project is eventually headed. Only the clock, reset IC and EEPROM would need to be substituted at the moment.&lt;/p&gt;
&lt;p&gt;This blog post is only a snapshot of the project. You can check the current status on GitHub &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/65816-computer&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;here&lt;/a&gt;.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>A first look at the 65C816 processor</title>
        <link>https://mike42.me/blog/2022-01-a-first-look-at-the-65c816-processor</link>
        <pubDate>Thu, 27 Jan 2022 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2022-01-a-first-look-at-the-65c816-processor</guid>
        <description>&lt;p&gt;The 65C816 is an interesting processor from the 1980&amp;rsquo;s. I recently wired one up on a breadboard, and I&amp;rsquo;ll be blogging here about my attempts to build something useful with it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-01-a-first-look-at-the-65c816-processor/2022-01-65c816-cpu.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;955&#34;
	srcset=&#34;https://mike42.me/blog/2022-01-a-first-look-at-the-65c816-processor/2022-01-65c816-cpu_hu_c0a628da39d3ba0d.jpg 480w, https://mike42.me/blog/2022-01-a-first-look-at-the-65c816-processor/2022-01-65c816-cpu_hu_514104c414994ca0.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;134&#34;
		data-flex-basis=&#34;321px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;how-i-got-here&#34;&gt;How I got here
&lt;/h2&gt;&lt;p&gt;I spent a couple of months last year designing and building &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/6502-computer&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;a computer based on the 65C02&lt;/a&gt;, an old 8 bit processor. I wanted to create a hardware platform for running 6502 assembly programs. This was successful, and I learned a &lt;em&gt;lot&lt;/em&gt; about how computers work while building and programming it.&lt;/p&gt;
&lt;p&gt;This has got me interested in the 65C816, which is a later extension of the same architecture. The only well-known systems which used it were the &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Super_Nintendo_Entertainment_System&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Super Nintendo&lt;/a&gt; and &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Apple_IIGS&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Apple IIGS&lt;/a&gt;. From a programmer&amp;rsquo;s point of view, this chip seems far more capable than its pre-decessor, though developer tools are a bit scarce.&lt;/p&gt;
&lt;h2 id=&#34;new-project-goals&#34;&gt;New project goals
&lt;/h2&gt;&lt;p&gt;My plan is to build a modern computer which uses the 65C816 CPU, so that I can really learn how it works.&lt;/p&gt;
&lt;p&gt;Over a few revisions, I am aiming to build up to a system with a serial connection for simple text I/O, a modest clock speed, and 1 megabyte of static RAM.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve researched some existing designs, and settled on two simple constraints to give this project its own character.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use only in-production parts.&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t use an FPGA or microcontroller to bootstrap the system.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This will ensure that I am learning what it takes to build a computer around this processor, and not just offloading the tricky parts to more powerful device with better tooling. I also hope this increases the accessibility of the design, since anybody could build it without needing to obtain obscure retro parts.&lt;/p&gt;
&lt;p&gt;I am not avoiding programmable logic entirely though. Where classic designs often used custom chips, I will be &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-10-programming-plds-with-open-source-software&#34; &gt;using ATF22V10 PLD&amp;rsquo;s&lt;/a&gt;. I will also leave the door open adding video output via a microcontroller-based terminal emulator in the future.&lt;/p&gt;
&lt;p&gt;Lastly, I&amp;rsquo;m selecting parts with a view to converting everything from 5 volts to 3.3 volts part-way through the project, which will open up many possibilities.&lt;/p&gt;
&lt;p&gt;Other than the Apple IIGS and Super Nintendo, there are three hobbyist designs which I&amp;rsquo;m using for inspiration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;BCS Technology&amp;rsquo;s &lt;a class=&#34;link&#34; href=&#34;http://sbc.bcstechnology.net/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;proof of concept W65C816S computers&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Gordon Henderson&amp;rsquo;s &lt;a class=&#34;link&#34; href=&#34;https://projects.drogon.net/65816-ruby/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Ruby &amp;lsquo;816&lt;/a&gt; project.&lt;/li&gt;
&lt;li&gt;Adrien Kohlbecker&amp;rsquo;s &lt;a class=&#34;link&#34; href=&#34;https://github.com/adrienkohlbecker/65C816&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;65C816 project&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;a-quick-note-about-open-source&#34;&gt;A quick note about open source
&lt;/h2&gt;&lt;p&gt;It&amp;rsquo;s never been a stated goal of this blog, but wherever possible, I use open source tools, and produce open source software. I expect that to be difficult for this project. The 65C816 not widely used, and most hobbyist code for the CPU is licensed as source-available freeware, with restrictions on commercial use.&lt;/p&gt;
&lt;p&gt;I would like to be able to release my code under an &lt;a class=&#34;link&#34; href=&#34;https://opensource.org/osd&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;OSI-approved open source license&lt;/a&gt;, and have the option of incorporating copyleft code later on. Unfortunately for me, it seems I will need to write a lot of low-level code from scratch to get this kind of licensing certainty. I will be working primarily in assembly language, though C code would be very useful, so I will certainly be spending some time investigating compiler options along the way.&lt;/p&gt;
&lt;h2 id=&#34;a-smoke-test&#34;&gt;A smoke test
&lt;/h2&gt;&lt;p&gt;This is the first iteration of the design, which will live for now on a series of solderless breadboards.&lt;/p&gt;
&lt;p&gt;This is simply a 65C816 processor, being fed a hard-coded &lt;code&gt;NOP&lt;/code&gt; (no-operation) command. When it runs, the lights show the address bus counting upwards, as the CPU program counter increases.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-01-a-first-look-at-the-65c816-processor/2022-01-65c816-nop.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;826&#34;
	srcset=&#34;https://mike42.me/blog/2022-01-a-first-look-at-the-65c816-processor/2022-01-65c816-nop_hu_646dc9eae1099435.jpg 480w, https://mike42.me/blog/2022-01-a-first-look-at-the-65c816-processor/2022-01-65c816-nop_hu_8ab6e0449a72d957.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;154&#34;
		data-flex-basis=&#34;371px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;RDY&lt;/code&gt;, &lt;code&gt;ABORTB&lt;/code&gt;, and &lt;code&gt;BE&lt;/code&gt; inputs are connected to +5v through resistors, while &lt;code&gt;RESB&lt;/code&gt;, &lt;code&gt;NMIB&lt;/code&gt;, &lt;code&gt;IRQB&lt;/code&gt; are connected to +5v directly. The &lt;code&gt;NOP&lt;/code&gt; opcode is fed to the CPU over the data bus, by making the pattern &lt;code&gt;11101010&lt;/code&gt; (&lt;code&gt;0xEA&lt;/code&gt;) with 1k resistors. The schematic for this is below.&lt;/p&gt;
&lt;p&gt;&lt;div class=&#34;img-canvas-outer&#34;&gt;
&lt;a href=&#34;https://mike42.me/blog/2022-01-a-first-look-at-the-65c816-processor/2022-01-65c816_nop.svg&#34; class=&#34;img-canvas-link  &#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://mike42.me/blog/2022-01-a-first-look-at-the-65c816-processor/2022-01-65c816_nop.svg&#34;
	
	
	
	loading=&#34;lazy&#34;
	
	
	    class=&#34;img-canvas-inner&#34; 
	
&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;The clock is an LM555 timer, fed through a 74AC04 inverter, because the rise and fall times on a 555 are not fast enough. The clock speed is 6.9Hz (that is not a typo), since R1 is 10 kΩ, and R2 is 100 kΩ, and the capacitor is 1 µF.&lt;/p&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next steps
&lt;/h2&gt;&lt;p&gt;This is going to be a long project, which I will develop incrementally. The next step will be adding ROM, RAM, glue logic and a 65C22 I/O chip.&lt;/p&gt;
&lt;p&gt;I am also testing alternatives to the 65C51N UART chip, which I found quite limited when I &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer&#34; &gt;used it for my last project&lt;/a&gt;.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Rendering my 6502 computer project in Blender</title>
        <link>https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender</link>
        <pubDate>Thu, 13 Jan 2022 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender</guid>
        <description>&lt;p&gt;For the past couple of months, I&amp;rsquo;ve been working on building a 6502-based computer from scratch.&lt;/p&gt;
&lt;p&gt;In a previous blog post, I wrote about &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender&#34; &gt;designing a 3D-printed enclosure&lt;/a&gt; for this project in Blender.&lt;/p&gt;
&lt;p&gt;During this build, I needed to wait for some parts, so I had some time to see what I could do with the 3D models of the case and circuit board. I ended up animating the assembly process, and learned a couple of tricks along the way.&lt;/p&gt;

      &lt;div
          style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
        &lt;iframe
          src=&#34;https://player.vimeo.com/video/644731273?dnt=0&#34;
            style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allow=&#34;fullscreen&#34;&gt;
        &lt;/iframe&gt;
      &lt;/div&gt;

&lt;h2 id=&#34;splitting-components-and-pcb&#34;&gt;Splitting components and PCB
&lt;/h2&gt;&lt;p&gt;I already had a 3D model of the circuit board and components. This was initially exported from KiCad, in STEP format. I then used FreeCAD to convert it from STEP to STL, which I imported into Blender for designing the case. I also repeated this export with some different footprints, since I needed sockets and microchips.&lt;/p&gt;
&lt;p&gt;It is a challenge to make this look good, because the circuit board and all components come in as one object, and have lost all of the detail from the KiCad 3D view.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender01-scaled.jpg&#34;
	width=&#34;2560&#34;
	height=&#34;1353&#34;
	srcset=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender01-scaled_hu_2ea0bbc1e994c88a.jpg 480w, https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender01-scaled_hu_86965290e13c6f64.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;189&#34;
		data-flex-basis=&#34;454px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I spent a lot of time splitting objects, then selecting faces so that I could assign different materials. I&amp;rsquo;m using a free BlenderKit account for materials, and using procedural materials where possible.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender02-scaled.jpg&#34;
	width=&#34;2560&#34;
	height=&#34;1355&#34;
	srcset=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender02-scaled_hu_7f7c68ff1af0b3f.jpg 480w, https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender02-scaled_hu_8634f4bc16450ad.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;188&#34;
		data-flex-basis=&#34;453px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I also modeled the DC barrel jack and slide switches, which were the first of many components which were missing from the original KiCad export. Still, something was missing.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender03-scaled.jpg&#34;
	width=&#34;2560&#34;
	height=&#34;1355&#34;
	srcset=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender03-scaled_hu_a01f5c09ddcb7650.jpg 480w, https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender03-scaled_hu_ca7d071abb399804.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;188&#34;
		data-flex-basis=&#34;453px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;adding-missing-details&#34;&gt;Adding missing details
&lt;/h2&gt;&lt;p&gt;I thought that the PCB in the previous image was too bare. The real PCB uses plated through-holes, and almost every hole in a real PCB has a shiny solder pad around it.&lt;/p&gt;
&lt;p&gt;To fix this, I exported the front solder-mask layer from KiCad as an SVG, which looks something like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender04.png&#34;
	width=&#34;1280&#34;
	height=&#34;1116&#34;
	srcset=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender04_hu_5e7422291e5f2936.png 480w, https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender04_hu_b7e338b8653ba609.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;114&#34;
		data-flex-basis=&#34;275px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I imported this SVG into Blender, scaled it to fit the PCB, extruded it, then went through a series of boolean modifiers. This resulted in a new object which contained every part of the PCB which was not covered in solder mask. I assigned this a shiny metal material.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender05.png&#34;
	width=&#34;3840&#34;
	height=&#34;2032&#34;
	srcset=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender05_hu_35c852f6f05b5765.png 480w, https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender05_hu_6d9e93a302637271.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;188&#34;
		data-flex-basis=&#34;453px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;After this was applied, I subtracted this from the original PCB model, giving the parts of the PCB which are covered in solder mask.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender06.png&#34;
	width=&#34;3840&#34;
	height=&#34;2032&#34;
	srcset=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender06_hu_16ff634bd69d7e82.png 480w, https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender06_hu_a2bddd9206bcfa4b.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;188&#34;
		data-flex-basis=&#34;453px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Showing both of these at the same time, I have a PCB with solder pads and plated through-holes.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender07-scaled.jpg&#34;
	width=&#34;2560&#34;
	height=&#34;1355&#34;
	srcset=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender07-scaled_hu_4fc9f8f959ddf35d.jpg 480w, https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender07-scaled_hu_cab166d1360ffdd4.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;188&#34;
		data-flex-basis=&#34;453px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;importing-the-silkscreen&#34;&gt;Importing the silkscreen
&lt;/h2&gt;&lt;p&gt;This still was not right. On the real PCB, everything is labelled.&lt;/p&gt;
&lt;p&gt;I exported the front silkscreen layer from KiCad as an SVG. This layer looks something like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender08.png&#34;
	width=&#34;1280&#34;
	height=&#34;1125&#34;
	srcset=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender08_hu_f3f8b909dc2eac51.png 480w, https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender08_hu_ba6899d51112b6d4.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;113&#34;
		data-flex-basis=&#34;273px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I then used InkScape to change this to white text on a transparent background, before finally exporting it as a PNG. I mixed this into the procedural texture which I was using for the PCB, using the transparency as the mix factor. As a final touch, I also exported the front copper layer, and used this as the displacement input for the final material. The nodes are shown in the screen capture below.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender09-scaled.jpg&#34;
	width=&#34;2560&#34;
	height=&#34;1348&#34;
	srcset=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender09-scaled_hu_70034b06ea43d1a9.jpg 480w, https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender09-scaled_hu_f095f7b086c8df01.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;189&#34;
		data-flex-basis=&#34;455px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This allows me to render a PCB which looks &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb&#34; &gt;a lot like the real thing&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender10.jpg&#34;
	width=&#34;2558&#34;
	height=&#34;1614&#34;
	srcset=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender10_hu_20364a2113b006cf.jpg 480w, https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender10_hu_3c84b005e4cc1da.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;158&#34;
		data-flex-basis=&#34;380px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;uv-unwrapping-everything&#34;&gt;UV unwrapping everything
&lt;/h2&gt;&lt;p&gt;In the earlier render, all of the chips had clear surfaces, while real chips are covered with text and logos.&lt;/p&gt;
&lt;p&gt;I created small transparent/brown PNG images for each chip, using Inkscape, then UV unwrapped the chips. I mixed the logo into the texture, much the same as I did for the PCB.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender11.jpg&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender11_hu_79ab17477b730c34.jpg 480w, https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender11_hu_84fa5ebd5ca3bad7.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I also UV unwrapped each resistor, in order to paint on the correct colour codes. This was perhaps the most egregious waste of time in this whole thing.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender12-scaled.jpg&#34;
	width=&#34;2560&#34;
	height=&#34;1355&#34;
	srcset=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender12-scaled_hu_2ef4a18e19fabe64.jpg 480w, https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender12-scaled_hu_f22e3fa31bce7270.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;188&#34;
		data-flex-basis=&#34;453px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;adding-final-parts&#34;&gt;Adding final parts
&lt;/h2&gt;&lt;p&gt;There were plenty more parts which I couldn&amp;rsquo;t export from KiCad, and needed to model from scratch. I used the bolt factory add-on to create screws, nuts, and hex standoffs (both a screw and a nut, combined).&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender13-scaled.jpg&#34;
	width=&#34;2560&#34;
	height=&#34;1348&#34;
	srcset=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender13-scaled_hu_f370b67247ad438b.jpg 480w, https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender13-scaled_hu_66b43820dea1aedb.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;189&#34;
		data-flex-basis=&#34;455px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I also added power and reset buttons (which are partly threaded), plus the speaker. I decided not to add wires, since it would be beyond my skill at the moment.&lt;/p&gt;
&lt;p&gt;When everything is displayed at once, a lot of this detail is hidden behind other objects.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender14.jpg&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender14_hu_14edfcf67a9d9f29.jpg 480w, https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender14_hu_34be4059bd1f3a03.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;animating&#34;&gt;Animating
&lt;/h2&gt;&lt;p&gt;With that last render, I decided to see if I could make an animation of all of the parts coming together. I&amp;rsquo;ve never animated anything in Blender, so I had a lot to learn.&lt;/p&gt;
&lt;p&gt;I added a tracking constraint to the camera, which is panning around an invisible object on the table, and animated everything using key-framed movement. Parts are raised out of view with slightly randomised rotation/location before falling into place.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender15.png&#34;
	width=&#34;3840&#34;
	height=&#34;2022&#34;
	srcset=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender15_hu_3010a69177f625f0.png 480w, https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender15_hu_c67449d653e2a603.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;189&#34;
		data-flex-basis=&#34;455px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;rendering&#34;&gt;Rendering
&lt;/h2&gt;&lt;p&gt;I exported the animation from Blender as 360 separate 1920 x 1080 images, to be played back at 30 frames per second. I would normally use ffmpeg to convert an image sequence into a video, but I wanted to try adding an audio track.&lt;/p&gt;
&lt;p&gt;I imported the rendered animation into &lt;a class=&#34;link&#34; href=&#34;https://kdenlive.org/en/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Kdenlive&lt;/a&gt;, which can process image sequences (the button is &amp;ldquo;Add clip&amp;rdquo; / &amp;ldquo;Import as sequence&amp;rdquo;), fetched a track from the Free Music Archive (Scanglobe - Current. CC BY-NC), and rendered the project.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender16-scaled.jpg&#34;
	width=&#34;2560&#34;
	height=&#34;1449&#34;
	srcset=&#34;https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender16-scaled_hu_13da3bf1d2c886a9.jpg 480w, https://mike42.me/blog/2022-01-rendering-my-6502-computer-project-in-blender/2022-01-blender16-scaled_hu_c6b3baa0249e17bb.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;176&#34;
		data-flex-basis=&#34;424px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap-up
&lt;/h2&gt;&lt;p&gt;I wanted to get a textured, 3D model of this entire project so that I could easily illustrate documentation and project pages. I definitely achieved this, though working with the exported circuit board and components in Blender was tedious.&lt;/p&gt;
&lt;p&gt;The version of Blender used here is 2.93, and the files were exported from KiCad 5.1.10.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Assembling my 6502 computer</title>
        <link>https://mike42.me/blog/2021-12-assembling-my-6502-computer</link>
        <pubDate>Thu, 30 Dec 2021 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2021-12-assembling-my-6502-computer</guid>
        <description>&lt;p&gt;I recently finished assembling my 6502 computer, so that the whole project is housed in a 3D-printed case.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-01.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-01_hu_c4151b5dedb5129e.jpg 480w, https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-01_hu_55785c13d27f3210.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This is something that should be easy. I already blogged about &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender&#34; &gt;making the case&lt;/a&gt;, and &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb&#34; &gt;making the circuit board&lt;/a&gt;. All that is left is to put the board in the case, right? Well thanks to some mistakes on my part, things are not quite so simple.&lt;/p&gt;
&lt;h2 id=&#34;more-parts&#34;&gt;More parts
&lt;/h2&gt;&lt;p&gt;I needed quite a few parts to finish this project, including a power button, reset button, hex standoffs, short screws, and rubber feet. Since this is the first time I&amp;rsquo;m hitting this stage of a project, I also needed to buy a Du Pont connector kit, stranded wire, heat-shrink tube, and glue.&lt;/p&gt;
&lt;p&gt;I have been powering the project from a USB/serial adapter, so I also bought a new one to install permanently. A full parts list is available in &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/6502-computer/tree/main/hardware#additional-parts-to-install-in-case&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;the GitHub repository for this project&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-02.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-02_hu_b6ad133dcf98b879.jpg 480w, https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-02_hu_97420aaa323e9d7c.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I also needed to widen the hole for the reset button due to a mix-up. The specific part I used requires a 7mm hole, while I had designed the case for a button with a 6mm hole.&lt;/p&gt;
&lt;h2 id=&#34;making-connections&#34;&gt;Making connections
&lt;/h2&gt;&lt;p&gt;The first step was to modify the board so that it would be compatible with the new UART, which involved de-soldering the female pin headers which I installed previously, and replacing them with male pin headers. I used only a soldering iron, solder wick, and flux for de-soldering, and it was not a fun process. The board survived, so I&amp;rsquo;ll call it a success.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-03.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-03_hu_24434f58cbec9a1b.jpg 480w, https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-03_hu_1ee64959908cfe1d.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Next, I soldered wires to the underside of the board for the power button, reset button, and &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-10-re-creating-the-worlds-worst-sound-card&#34; &gt;speaker&lt;/a&gt; to connect. Each of these is a pair of wires, soldered at one end, and a 2-pin female Du Pont connector on the other.&lt;/p&gt;
&lt;p&gt;I attached corresponding connectors on the buttons and speaker. The power button also has an in-built LED, and there are plenty of places to power this from the board&amp;rsquo;s expansion headers. I added a 2-pin female Du Pont connector, plus a resistor, neatly hidden by heat-shrink.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-04.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-04_hu_2b2131f46896977b.jpg 480w, https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-04_hu_73b0c54a508d8835.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I checked everything with a multimeter before powering it on. The UART pins were connected correctly to the 65C51N chip and ground. No continuity between the board&amp;rsquo;s power and the external power unless the power button is pressed, no continuity between the reset line and ground unless the reset button is pressed, and so on.&lt;/p&gt;
&lt;h2 id=&#34;troubleshooting&#34;&gt;Troubleshooting
&lt;/h2&gt;&lt;p&gt;When I powered on the computer, nothing came up on the terminal, which means that I broke something. I tested some voltages, and found the computer was stuck in reset.&lt;/p&gt;
&lt;p&gt;The reset signal on the 6502 is active-low, and I&amp;rsquo;ve &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer&#34; &gt;added a supervisory IC&lt;/a&gt;. Any time the reset signal is low, or the power drops below a minimum voltage, this IC holds it low for 150ms before returning it to +5v. I was confident that the reset buttons and power voltage were fine, so I suspected that one one of the other chips could be causing the problem.&lt;/p&gt;
&lt;p&gt;Everything is socketed, so I removed the 65C51N and tested again. This chip is closest to the de-soldering work I was doing earlier, so I thought I may have damaged it.&lt;/p&gt;
&lt;p&gt;There was no change, so I started removing other chips, and found that after removing the CPU, the computer was no longer getting stuck in reset.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-05.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-05_hu_bcf7387876cccd6e.jpg 480w, https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-05_hu_76e7604627b7576e.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Following that lead, I found that one of the data bus lines, D4, was connected to the reset line. This would cause activity on the data bus to reset the computer, which would cause this problem.&lt;/p&gt;
&lt;p&gt;A quick look at the board in KiCad showed that at one of the points I had attached the reset button, D4 is 0.5mm away from the reset line.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-06.png&#34;
	width=&#34;2242&#34;
	height=&#34;1567&#34;
	srcset=&#34;https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-06_hu_4e08975d91b03c29.png 480w, https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-06_hu_9a012f176fd7040b.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;143&#34;
		data-flex-basis=&#34;343px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I de-soldered that wire and found a tiny break in the solder mask on D4. This was easy enough to fix, I simply attached the wire for the external reset button elsewhere.&lt;/p&gt;
&lt;p&gt;I also bent the CPU pins when re-installing, but after fixing that, I was back in business.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-07.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-07_hu_9baa09b4c661a36.jpg 480w, https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-07_hu_c96a9f2f1ffa16e4.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;sd-card-changes&#34;&gt;SD card changes
&lt;/h2&gt;&lt;p&gt;I have been writing some &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer&#34; &gt;test programs which use a microSD card&lt;/a&gt; via one of the 65C22 I/O ports, and wanted to fit this in the case as well.&lt;/p&gt;
&lt;p&gt;I swapped the &lt;a class=&#34;link&#34; href=&#34;https://www.adafruit.com/product/254&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Adafruit ADA254&lt;/a&gt; microSD break-out for the &lt;a class=&#34;link&#34; href=&#34;https://www.sparkfun.com/products/13743&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;SparkFun DEV-13743&lt;/a&gt;. It is slightly smaller, includes pull-up resistors, and still provides level-shifting.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-08.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-08_hu_6a2a140fe6acac02.jpg 480w, https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-08_hu_3b9c41014b2370ac.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I made a small adapter by attaching a female pin header to a Du Pont housing with superglue. I couldn&amp;rsquo;t get the &amp;ldquo;card detect&amp;rdquo; feature to work, so I wired it up differently to my previous blog post, and &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/6502-computer/commit/7214ec9b90c810158a920ffae037a3b0e7772180&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;updated the code to match&lt;/a&gt;. Details of the new wiring is &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/6502-computer/tree/main/hardware#additional-parts-to-install-microsd&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-09.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-09_hu_bcd3ee6f0c0406d2.jpg 480w, https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-09_hu_33263f36c8dea4d.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I also added some masking tape when I installed this to prevent any short circuits. The metal on the outside of the microSD socket is connected to ground, and it could touch some IC pins.&lt;/p&gt;
&lt;h2 id=&#34;quick-lessons&#34;&gt;Quick lessons
&lt;/h2&gt;&lt;p&gt;This is only a learning project for me, so I am trying to take some lessons away from each part of it.&lt;/p&gt;
&lt;p&gt;The high-level lessons would be to plan for external connections before building the PCB, and to have all parts on hand before designing the case. That would have saved a lot of re-work, though adapting a design without starting from scratch is a valuable skill in itself.&lt;/p&gt;
&lt;p&gt;If I were starting from scratch, I would add pin headers to the board for connecting the power and reset buttons instead of including buttons on the board, and remove the (now unused) DC barrel jack as a power input. I would also make the board larger, and the case taller, so that everything is less cramped. It takes a lot of force to remove chips from machined pin sockets, and the board is too compact to get a screwdriver under the chips.&lt;/p&gt;
&lt;p&gt;SD card support is also a bit of a hack, and could be built-in to the board with some effort.&lt;/p&gt;
&lt;h2 id=&#34;final-results&#34;&gt;Final results
&lt;/h2&gt;&lt;p&gt;I now have a fully self-contained 8 bit computer, and it looks more like a finished project than an in-progress experiment. It &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-09-porting-basic-to-my-6502-computer&#34; &gt;boots to BASIC&lt;/a&gt;, or with the flip of a switch, launches a ROM which allows me to &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer&#34; &gt;load machine code assembled on my PC&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With the lid removed, I can access the 40-pin expansion header, and one spare I/O port.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-10.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-10_hu_f0d6169b40b67838.jpg 480w, https://mike42.me/blog/2021-12-assembling-my-6502-computer/2021-12-6502-computer-10_hu_936f5278db174188.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The hardware side of this project is now done, and I have a platform for testing any 6502 assembly code on real hardware.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Adding an SD card reader to my 6502 computer</title>
        <link>https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer</link>
        <pubDate>Thu, 16 Dec 2021 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer</guid>
        <description>&lt;p&gt;I recently attempted to add SD card support to my home-built 6502 computer.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer/2021-12-sd-01.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer/2021-12-sd-01_hu_10f8c12ded8bcc8d.jpg 480w, https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer/2021-12-sd-01_hu_e9c6c044aba42804.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This was successful, but more challenging than I expected. This blog post is just a few things that I learned along the way.&lt;/p&gt;
&lt;h2 id=&#34;background&#34;&gt;Background
&lt;/h2&gt;&lt;p&gt;SD cards are a popular way to add storage to electronics projects. In my case, I will be using the SD card in SPI mode. My home-built computer has an expansion port with some GPIO pins, which should be sufficient for this.&lt;/p&gt;
&lt;p&gt;My basic plan was to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;write some test data to an SD card from a modern computer&lt;/li&gt;
&lt;li&gt;interface the SD card to my home-built 6502 computer&lt;/li&gt;
&lt;li&gt;write a 6502 assembly program to print out the test data&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since this is a learning project, I started from scratch, and avoided reading any existing implementations of SPI or SD cards before jumping in.&lt;/p&gt;
&lt;h2 id=&#34;test-data&#34;&gt;Test data
&lt;/h2&gt;&lt;p&gt;I started this project by generating a small test file, repeating each character in the alphabet 512 times.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;echo abcdefghijklmnopqrstuvwxyz | fold -w1 | while read line; do yes $line | head -n512 ; done | tr -d &amp;#34;\n&amp;#34; &amp;gt; disk.img
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It takes a one-line shell command to write this image to an SD card on all good operating systems, or a few clicks in the disk imaging utility.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dd if=disk.img of=/dev/my_sd_card
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;My laptop has an SD card slot, but I also have Windows on it at the moment, which turned this into a far larger problem than I could have imagined.&lt;/p&gt;
&lt;p&gt;Driver support for this particular SD card reader was dropped in Windows 10, there are no built-in tools for imaging disks on Windows, and I had to try multiple tools before I could find one which would write a raw disk image (one which does not contain a valid filesystem).&lt;/p&gt;
&lt;p&gt;In retrospect, this was the first of many lessons about not having the right tools for this project.&lt;/p&gt;
&lt;h2 id=&#34;physical-interface&#34;&gt;Physical interface
&lt;/h2&gt;&lt;p&gt;I connected an SD card module to my 6502 computer, via a breadboard. I used a module which could level-shift, because my computer runs at 5V, where SD cards usually run at 3.3V. This particular module is an &lt;a class=&#34;link&#34; href=&#34;https://www.adafruit.com/product/254&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Adafruit ADA254&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer/2021-12-sd-02.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer/2021-12-sd-02_hu_98cfc6eaa4186cbe.jpg 480w, https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer/2021-12-sd-02_hu_c9955e324a8ee880.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I also added pull-up resistors to all of the data lines, after noticing that there were several sitations where they would float. The wiring I used is:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer/2021-12-sd-03.png&#34;
	width=&#34;1024&#34;
	height=&#34;1363&#34;
	srcset=&#34;https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer/2021-12-sd-03_hu_2fd054ef6e521999.png 480w, https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer/2021-12-sd-03_hu_a45108712e11cbd9.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;75&#34;
		data-flex-basis=&#34;180px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The full schematic for my 6502 computer is on &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb&#34; &gt;this blog post&lt;/a&gt;, while the schematic for the SD card module is online &lt;a class=&#34;link&#34; href=&#34;https://learn.adafruit.com/adafruit-micro-sd-breakout-board-card-tutorial/download&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;software-part-1&#34;&gt;Software: Part 1
&lt;/h2&gt;&lt;p&gt;With some test data and a hardware interface, I got to the third step, which was to read data from the SD card. I was completely unprepared for how tricky it is to do this from scratch, without the right experience or debugging tools.&lt;/p&gt;
&lt;p&gt;As a quick re-cap, my development environment is still very limited: I am &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-05-intellij-plugin-for-6502-assembly-language&#34; &gt;writing 6502 assembly on a modern computer&lt;/a&gt;, and I have the ability to &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer&#34; &gt;send the assembled program&lt;/a&gt; to my home-built 6502 computer over a serial connection.&lt;/p&gt;
&lt;p&gt;I started by using lecture notes from the University at Buffalo&amp;rsquo;s EE-379 course, available online &lt;a class=&#34;link&#34; href=&#34;http://www.dejazzer.com/ee379/lecture_notes/lec12_sd_card.pdf&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;here&lt;/a&gt;. This describes SPI, SD card command structure, and the sequence to initialise a card.&lt;/p&gt;
&lt;p&gt;The two protocols I needed to implement are SPI, which transfers the bits, plus the SD card commands which run over that. I had to write quite a lot of code with no feedback, because it takes several commands before SD cards are ready to work with in SPI mode, and the exact details vary depending on the generation of card (SDHC vs SDXC, etc).&lt;/p&gt;
&lt;p&gt;After days of debugging, I was unable to get a response from the SD card. With few other options, I started filling my code with the assembly-language equivalent of &lt;code&gt;print&lt;/code&gt; statements, and found that every byte from the SD card was the default &lt;code&gt;FF&lt;/code&gt;. This means &amp;rsquo;no data&amp;rsquo; in this context.&lt;/p&gt;
&lt;p&gt;Print statements also slowed the program down to a crawl, which allowed me to use a pizeo buzzer to listen to each line. This clicks each time a signal changes between 0 and 1, so I was able to check that each line had the expected activity. I found that the SD card was sending responses, but that the computer was not receiving them, because they were not connected to eachother on the breadboard.&lt;/p&gt;
&lt;h2 id=&#34;software-part-2&#34;&gt;Software: Part 2
&lt;/h2&gt;&lt;p&gt;After connecting the card correctly, I could see responses for the first time. The format here is &lt;code&gt;byte sent / byte received&lt;/code&gt;, with line breaks between commands.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SD card detected
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;40/7f 00/ff 00/ff 00/ff 00/ff 95/ff ff/ff ff/01 ff/ff
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;48/7f 00/ff 00/ff 01/ff aa/ff 0f/ff ff/ff ff/09 ff/ff ff/ff ff/ff ff/ff
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;7a/7f 00/ff 00/ff 00/ff 00/ff 75/ff ff/ff ff/01 ff/00 ff/ff ff/80 ff/00 ff/ff ff/ff
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The correct initialisation sequence depends on the type of SD card, and I spent a lot of time going through each possibility, looking for one one which worked. When this failed, I found this summary online, which includes more information about decoding the responses: &lt;a class=&#34;link&#34; href=&#34;http://chlazza.nfshost.com/sdcardinfo.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Secure Digital (SD) Card Spec and Info&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As it turned out, I was not sending the correct CRC for &lt;code&gt;CMD8&lt;/code&gt;, and a CRC error is indicated by the &lt;code&gt;09&lt;/code&gt; (binary &lt;code&gt;0000 1001&lt;/code&gt;) response to the second command above. Each bit in the response has a different meaning, and I had mistaken this for indicating an unsupported command, which is expected for some card types.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a good thing that I had this problem, because searching for the CRC algorithm turned up this &lt;a class=&#34;link&#34; href=&#34;http://www.rjhcoding.com/avrc-tutorials-home.php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;collection of AVR C tutorials&lt;/a&gt;, which includes a 4-part series on implementing SD card support.&lt;/p&gt;
&lt;p&gt;I noticed that all of the command examples were wrapped with code like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    // assert chip select
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    SPI_transfer(0xFF);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    CS_ENABLE();
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    SPI_transfer(0xFF);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    // ... code to send a command...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    // deassert chip select
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    SPI_transfer(0xFF);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    CS_DISABLE();
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    SPI_transfer(0xFF);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Later on, I had a problem where responses were sometimes mis-aligned by one bit. When I also tried &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/6502-computer/commit/9a0eb84a9529edeba201b527bf64291a86a78f92#diff-b3a8f7e01763183fafb34235221f31bcc35d1ecfe07fca4714d2399ca524c12aR280&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;sending empty bytes between commands, while the SD card is not selected&lt;/a&gt;, these problems disappeared entirely.&lt;/p&gt;
&lt;h2 id=&#34;software-part-3&#34;&gt;Software: Part 3
&lt;/h2&gt;&lt;p&gt;With the &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/6502-computer/blob/9a0eb84a9529edeba201b527bf64291a86a78f92/rom/programs/sd_test.s&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;initialisation code complete&lt;/a&gt;, I could finally request data from the SD card.&lt;/p&gt;
&lt;p&gt;Data on an SD card is arranged in 512-byte blocks by default. I wrote a routine to read one block of data from the SD card into RAM, plus a routine to print sections of RAM.&lt;/p&gt;
&lt;p&gt;The result was a program which prints the first kilobyte of the SD card, which is the letter &lt;code&gt;a&lt;/code&gt; 512 times, followed by the letter &lt;code&gt;b&lt;/code&gt; 512 times.&lt;/p&gt;
&lt;p&gt;This screen capture shows the output of a program matching a &lt;code&gt;hexdump&lt;/code&gt; of the test file, which is exactly what I was aiming for.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer/2021-12-sd-04.png&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer/2021-12-sd-04_hu_6c937da10380c78d.png 480w, https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer/2021-12-sd-04_hu_431f89306f79f7f4.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The full code is too long to include in a blog post, but can be found in the repository for this project, &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/6502-computer&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/6502-computer&lt;/a&gt; on GitHub.&lt;/p&gt;
&lt;h2 id=&#34;some-lessons&#34;&gt;Some lessons
&lt;/h2&gt;&lt;p&gt;While I was able to read data from an SD card, this took a long time, and there were several points where I nearly hit a dead-end.&lt;/p&gt;
&lt;p&gt;I couldn&amp;rsquo;t see what was happening at a hardware level, and I couldn&amp;rsquo;t compare my setup with one that worked, because I had never done anything similar before. Spot-the-difference is a powerful debugging tool, and by jumping straight into 6502 assembly, while avoiding existing 6502 implementations, I definitely made things difficult for myself.&lt;/p&gt;
&lt;p&gt;With that in mind, there are several ways I could have made this easier:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Better equipment. A logic analyser, an SD card writer, and spare SD cards would have been useful for testing.&lt;/li&gt;
&lt;li&gt;Building somewhere less-constrained first. I could have implemented this first on a Raspberry Pi, then ported the result to 6502 assembly. It would then be possible to verify my hardware setup by running existing code, while still getting the learning experience from writing my implementation from scratch. Note that this would have required a different SD card break-out board.&lt;/li&gt;
&lt;li&gt;Building something simpler first. For example, Ben Eater released a &lt;a class=&#34;link&#34; href=&#34;https://www.youtube.com/watch?v=MCi7dCBhVpQ&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;a YouTube video&lt;/a&gt; around the time I was working on this, where he reads from an SPI temperature sensor on a 6502 computer. It would be much easier to get started if I had used &lt;em&gt;any other&lt;/em&gt; SPI device on a 6502 first.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The next step in this project is to load programs from an SD card, which would require me to implement a filesystem. This is significantly more complex than what I&amp;rsquo;ve done here, and I know not to approach it the same way.&lt;/p&gt;
&lt;h2 id=&#34;more-equipment&#34;&gt;More equipment
&lt;/h2&gt;&lt;p&gt;I picked up a logic analyser, USB SD card reader, alternative SD card module, and a spare SD card.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer/2021-12-sd-05.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer/2021-12-sd-05_hu_14ee338b65cc1e2b.jpg 480w, https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer/2021-12-sd-05_hu_310fefcf88529214.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The logic analyser is compatible with &lt;a class=&#34;link&#34; href=&#34;https://sigrok.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;sigrok&lt;/a&gt;, which is open source. This is the first time I&amp;rsquo;ve used this software, and it can decode SD card commands running over SPI, among other things.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer/2021-12-sd-06.png&#34;
	width=&#34;3844&#34;
	height=&#34;2100&#34;
	srcset=&#34;https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer/2021-12-sd-06_hu_22a62d0bfd6c11ec.png 480w, https://mike42.me/blog/2021-12-adding-an-sd-card-reader-to-my-6502-computer/2021-12-sd-06_hu_603fc66a83e1759c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;183&#34;
		data-flex-basis=&#34;439px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The USB SD card reader will allow me to write disk images directly from my development environment, instead of copying them over to a laptop. I do most of my development from a virtual machine, and USB peripherals are easy to pass though.&lt;/p&gt;
&lt;p&gt;The alternative SD card module is from &lt;a class=&#34;link&#34; href=&#34;https://www.sparkfun.com/products/13743&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;SparkFun&lt;/a&gt;. Compared with the module I was using in this blog post, it has a smaller footprint, and includes the pull-up resistors. I&amp;rsquo;m hoping I can use this to fit an SD card into the &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender&#34; &gt;3D-printed enclosure for this project&lt;/a&gt;.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Implementing the XMODEM protocol for file transfer</title>
        <link>https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer</link>
        <pubDate>Thu, 02 Dec 2021 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer</guid>
        <description>&lt;p&gt;I recently &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb&#34; &gt;built a 6502-based computer from scratch&lt;/a&gt;, and I&amp;rsquo;m using it as a platform for testing 6502 assembly code. The software on this computer is currently very limited, and re-programming an EEPROM chip to test changes is a slow process.&lt;/p&gt;
&lt;p&gt;This blog post covers changes which I made to implement the XMODEM protocol, allowing me to upload programs over a serial connection.&lt;/p&gt;
&lt;h2 id=&#34;the-protocol-itself&#34;&gt;The protocol itself
&lt;/h2&gt;&lt;p&gt;I chose XMODEM because it&amp;rsquo;s the simplest protocol which is compatible with modern terminal software. All I need right now is the ability to place some data (machine code) into RAM, so that I can execute it.&lt;/p&gt;
&lt;p&gt;An important note that is that modern file transfer protocols would normally run over TCP/IP, while XMODEM runs over a serial connection. This works for me, since it&amp;rsquo;s the only interface I&amp;rsquo;ve got.&lt;/p&gt;
&lt;p&gt;For what it&amp;rsquo;s worth, XMODEM is also era-appropriate technology for this retro computer, since it was first implemented in 1977. The 6502 processor came out in 1975.&lt;/p&gt;
&lt;h2 id=&#34;implementation&#34;&gt;Implementation
&lt;/h2&gt;&lt;p&gt;Implementing XMODEM was the easy part of this process. There are existing 6502 assembly implementations which I could have used, but I decided to work from the description on the &lt;a class=&#34;link&#34; href=&#34;en.wikipedia.org/wiki/XMODEM&#34; &gt;Wikipedia article&lt;/a&gt; instead. This is partly to make sure I understand it, and partly to keep the software licensing of my ROM as clear as possible.&lt;/p&gt;
&lt;p&gt;I have the beginnings of a &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Shell_%28computing%29&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;shell&lt;/a&gt; for running commands from ROM, so I implemented two new commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rx&lt;/code&gt;, to receive a file over XMODEM and load it into memory.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;run&lt;/code&gt; to jump to the program&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To start the transfer, I found it useful to write a method for reading a character with a time-out. I already have &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer&#34; &gt;routines for reading and writing characters&lt;/a&gt; from serial.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Like acia_recv_char, but terminates after a short time if nothing is received
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;shell_rx_receive_with_timeout:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;ldy&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$ff
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;y_loop:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$ff
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;x_loop:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ACIA_STATUS&lt;/span&gt;              &lt;span class=&#34;c1&#34;&gt;; check ACIA status in inner loop
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$08                     ; mask rx buffer status flag
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;bne&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;rx_got_char&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;dex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;cpx&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;bne&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;x_loop&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;dey&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;cpy&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;bne&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;y_loop&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;clc&lt;/span&gt;                          &lt;span class=&#34;c1&#34;&gt;; no byte received in time
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;rts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;rx_got_char:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ACIA_RX&lt;/span&gt;                  &lt;span class=&#34;c1&#34;&gt;; get byte from ACIA data port
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sec&lt;/span&gt;                          &lt;span class=&#34;c1&#34;&gt;; set carry bit
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;rts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The entire receive process is around 60 lines of assembly code. The process involves ASCII NAK character repeatedly until a SOH character is received, which indicates the start of a 128 byte packet. All padding around each packet is discarded, and the payload is written to memory. This process is repeated until the end of transmission (EOT) is received.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Built-in command: rx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; recives a file over XMODEM protocol, and loads it into memory
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;USER_PROGRAM_START&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$0400&lt;/span&gt;   &lt;span class=&#34;c1&#34;&gt;; Address for start of user programs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;USER_PROGRAM_WRITE_PTR&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$00&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;; ZP address for writing user program
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;shell_rx_main:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;; Set pointers
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#&amp;lt;USER_PROGRAM_START   ; Low byte first
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;USER_PROGRAM_WRITE_PTR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#&amp;gt;USER_PROGRAM_START   ; High byte next
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;USER_PROGRAM_WRITE_PTR&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;; Delay so that we can set up file send
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#1                     ; wait ~1 second
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;shell_rx_sleep_seconds&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;; NAK, ACK once
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;shell_block_nak:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$15                   ; NAK gets started
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;acia_print_char&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;SPEAKER&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;; Click each time we send a NAK or ACK
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;shell_rx_receive_with_timeout&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;; Check in loop w/ timeout
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;bcc&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;shell_block_nak&lt;/span&gt;       &lt;span class=&#34;c1&#34;&gt;; Not received yet
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;cmp&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$01                   ; If we do have char, should be SOH
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;bne&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;shell_rx_fail&lt;/span&gt;         &lt;span class=&#34;c1&#34;&gt;; Terminate transfer if we don&amp;#39;t get SOH
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;shell_rx_block:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;; Receive one block
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;acia_recv_char&lt;/span&gt;         &lt;span class=&#34;c1&#34;&gt;; Block number
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;acia_recv_char&lt;/span&gt;         &lt;span class=&#34;c1&#34;&gt;; Inverse block number
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;ldy&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#0                     ; Start at char 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;shell_rx_char:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;acia_recv_char&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;USER_PROGRAM_WRITE_PTR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;iny&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;cpy&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#128
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;bne&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;shell_rx_char&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;acia_recv_char&lt;/span&gt;         &lt;span class=&#34;c1&#34;&gt;; Checksum - TODO verify this and jump to shell_block_nak to repeat if not mathing
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$06                   ; ACK the packet
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;acia_print_char&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;SPEAKER&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;; Click each time we send a NAK or ACK
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;acia_recv_char&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;cmp&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$04                   ; EOT char, no more blocks
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;beq&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;shell_rx_done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;cmp&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$01                   ; SOH char, next block on the way
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;bne&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;shell_block_nak&lt;/span&gt;       &lt;span class=&#34;c1&#34;&gt;; Anything else fail transfer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;USER_PROGRAM_WRITE_PTR&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;; This next part moves write pointer along by 128 bytes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;cmp&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$00
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;beq&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;block_half_advance&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$00                   ; If low byte != 0, set to 0 and inc high byte
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;USER_PROGRAM_WRITE_PTR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;inc&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;USER_PROGRAM_WRITE_PTR&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;shell_rx_block&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;block_half_advance:&lt;/span&gt;         &lt;span class=&#34;c1&#34;&gt;; If low byte = 0, set it to 128
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$80
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;USER_PROGRAM_WRITE_PTR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;shell_rx_block&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;shell_rx_done:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$6                    ; ACK the EOT as well.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;acia_print_char&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;SPEAKER&lt;/span&gt;                &lt;span class=&#34;c1&#34;&gt;; Click each time we send a NAK or ACK
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#1                     ; wait a moment (printing does not work otherwise..)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;shell_rx_sleep_seconds&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;shell_rx_print_user_program&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;shell_newline&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;sys_exit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;shell_rx_fail:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;sys_exit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code is the first time that I&amp;rsquo;ve used the &amp;ldquo;Zero Page Indirect Indexed with Y&amp;rdquo; address mode. It uses a pointer to the program&amp;rsquo;s location, which is incremented 128 each time a packet is accepted.&lt;/p&gt;
&lt;p&gt;The index in the current packet is stored in the &lt;code&gt;Y&lt;/code&gt; register, allowing each incoming byte to be written to memory with one operation, which is called in a tight loop.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;USER_PROGRAM_WRITE_PTR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The other routines mentioned in this source listing are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;shell_rx_sleep_seconds&lt;/code&gt; - sleeps for the number of seconds in the &lt;code&gt;A&lt;/code&gt; register.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;shell_rx_print_user_program&lt;/code&gt; - prints the first 256 bytes of the program for verification.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The checksum is entirely ignored. Everything here is running on my desk, so I&amp;rsquo;m not too worried about transmission errors.&lt;/p&gt;
&lt;p&gt;After a few iterations, I was able to upload &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Lorem_ipsum&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;placeholder text&lt;/a&gt; to RAM.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer/2021-11-xmodem-test-01.png&#34;
	width=&#34;1576&#34;
	height=&#34;1066&#34;
	srcset=&#34;https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer/2021-11-xmodem-test-01_hu_1619c08ea7ac6d7.png 480w, https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer/2021-11-xmodem-test-01_hu_2e6ac9f3c53561a1.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;147&#34;
		data-flex-basis=&#34;354px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The screen capture shows 256 bytes of memory (2 packets in XMODEM). The ASCII &lt;code&gt;SUB&lt;/code&gt; character (&lt;code&gt;1a&lt;/code&gt; in hex) fills out unused bytes at the end, since everything sent over XMODEM needs to be a multiple of 128 bytes.&lt;/p&gt;
&lt;h2 id=&#34;assembling-some-programs&#34;&gt;Assembling some programs
&lt;/h2&gt;&lt;p&gt;I thought I was almost done at this point, but it turns out that writing a &amp;ldquo;Hello World&amp;rdquo; test program to run from RAM is easier said than done.&lt;/p&gt;
&lt;p&gt;I started by creating a new &lt;code&gt;ld65&lt;/code&gt; linker configuration which links code to run from address &lt;code&gt;$0400&lt;/code&gt; onwards, which is where programs are loaded into RAM. This system does not have a loader for &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Relocation_%28computing%29&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;re-locatable code&lt;/a&gt;, and absolute addresses are assigned by the linker.&lt;/p&gt;
&lt;p&gt;This is the configuration which I used for these tests. It has some flaws, but it&amp;rsquo;s good enough to place the &lt;code&gt;CODE&lt;/code&gt; segment in the right place.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# Test configuration for user programs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;MEMORY {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ZP:     start = $00,    size = $0100, type = rw, file = &amp;#34;&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    RAM:    start = $0100,  size = $0300, type = rw, file = &amp;#34;&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    MAIN:   start = $0400,  size = $1000, type = rw, file = %O;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ROM:    start = $C000,  size = $4000, type = ro, file = &amp;#34;&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SEGMENTS {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ZEROPAGE: load = ZP,  type = zp;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    BSS:      load = RAM, type = bss;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    CODE:     load = MAIN, type = ro;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    VECTORS:  load = ROM, type = ro,  start = $FFFA, optional=yes;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If I wanted my test program to terminate, then I needed to find the address of &lt;code&gt;sys_exit&lt;/code&gt; in ROM. This routine hands control back to the shell after a command completes.&lt;/p&gt;
&lt;p&gt;To get this, I re-assembled the ROM, but added the flag &lt;code&gt;--debug-info&lt;/code&gt; to the ca65 assembler, and &lt;code&gt;--dbgfile boot.dbg&lt;/code&gt; to the ld65 linker. This produces a text file, which contains the final address of each symbol.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sym id=45,name=&amp;#34;sys_exit&amp;#34;,addrsize=absolute,scope=0,def=28,ref=298+192+426+390+157,val=0xC11E,seg=0,type=lab
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The simplest test program I could come up with was:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; location in ROM
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sys_exit&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$c11e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.segment&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;CODE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;main:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;sys_exit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I was able to assemble this program to 3 bytes of binary and run it. It does absolutely nothing, and simply returns to the shell.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer/2021-11-xmodem-test-03.png&#34;
	width=&#34;1576&#34;
	height=&#34;1066&#34;
	srcset=&#34;https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer/2021-11-xmodem-test-03_hu_bd786e787e2a071f.png 480w, https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer/2021-11-xmodem-test-03_hu_372ae02d79933caa.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;147&#34;
		data-flex-basis=&#34;354px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;To extend this into a &amp;ldquo;Hello World&amp;rdquo; program, I needed to look up the location of two more routines in the ROM.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; locations of some functions in ROM
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;acia_print_char&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$c020&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;shell_newline&lt;/span&gt;   &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$c113&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;sys_exit&lt;/span&gt;        &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$c11e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.segment&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;CODE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;main:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;test_char:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;test_string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;X&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;beq&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;test_done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;acia_print_char&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;inx&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;test_char&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;test_done:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;shell_newline&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;sys_exit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;test_string:&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;.asciiz&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Test program&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This animation shows the process of uploading the binary and executing it via &lt;code&gt;minicom&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer/2021-11-xmodem-test-02.gif&#34;
	width=&#34;1468&#34;
	height=&#34;866&#34;
	
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;169&#34;
		data-flex-basis=&#34;406px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;There is nothing special about the invocation for minicom here, it&amp;rsquo;s just a bit-rate and device name, which in my case is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;minicom -b 19200 -D /dev/ttyUSB0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;automating-the-boring-stuff&#34;&gt;Automating the boring stuff
&lt;/h2&gt;&lt;p&gt;This approach is very fragile, because the code is full of hard-coded memory addresses.&lt;/p&gt;
&lt;p&gt;Any time I change the ROM, the addresses for these routines could change, and this program will no longer work.&lt;/p&gt;
&lt;p&gt;On any real architecture, applications call into the OS via system calls, or maybe a jump table for 8-bit systems. I don&amp;rsquo;t need a stable binary interface, and there is no userspace/kernel distinction, so I decided not to go down that path.&lt;/p&gt;
&lt;p&gt;Instead, I wrote a Python script to generate an assembly source file, using the same debug symbols which I was manually reading. This runs after each ROM build.&lt;/p&gt;
&lt;p&gt;The format is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.export&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;VIA_T2C_H&lt;/span&gt;                        &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$8009&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.export&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;VIA_T2C_L&lt;/span&gt;                        &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$8008&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.export&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;acia_delay&lt;/span&gt;                       &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$c02b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.export&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;acia_print_char&lt;/span&gt;                  &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$c014&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When this file is assembled, it doesn&amp;rsquo;t generate any code, but it does define all of the constants and labels from the ROM. When applications link against this, they can &lt;code&gt;.import&lt;/code&gt; anything which would be available to ROM-based code.&lt;/p&gt;
&lt;p&gt;The start of the above script is re-written as:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.import&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;acia_print_char&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;shell_newline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;sys_exit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This means that I have source compatibility, just not binary compatibility.&lt;/p&gt;
&lt;h2 id=&#34;bringing-everything-together&#34;&gt;Bringing everything together
&lt;/h2&gt;&lt;p&gt;With my initial goal achieved, I was still not happy with the development experience. I started to dig into the murky world of minicom scripting to see if I could automate the process of uploading/running programs, and found that it is indeed possible.&lt;/p&gt;
&lt;p&gt;The scripting capabilities of minicom do not appear to be widely used, and I needed to read through the source code to find ways to work around the problems I encountered.&lt;/p&gt;
&lt;p&gt;For example, the &amp;ldquo;send&amp;rdquo; command was sending characters too quickly for the target machine. There are hard-coded delays between commands in the interpreter, but you can&amp;rsquo;t use multiple &amp;ldquo;send&amp;rdquo; commands to slow things down, because it is also hard-coded to append a line ending each time.&lt;/p&gt;
&lt;p&gt;The fix was to use &lt;code&gt;!&amp;lt;&lt;/code&gt;, which sends the output of a command verbatim. This script uses &lt;code&gt;echo -n&lt;/code&gt; command to send each character individually. This is the exact same procedure as the animation in the previous section. First, the script types &amp;ldquo;rx&amp;rdquo;, then sends the file, then types &amp;ldquo;run&amp;rdquo;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# confirm we have a shell prompt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;send &amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sleep 0.1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# put into receive mode
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;expect &amp;#34;# &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sleep 0.1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;!&amp;lt; echo -n &amp;#39;r&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;!&amp;lt; echo -n &amp;#39;x&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;send &amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sleep 0.1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# send the program and wait for prompt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;! sx -q $TEST_PROGRAM 2&amp;gt; /dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;expect &amp;#34;# &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# run program
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sleep 0.1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;!&amp;lt; echo -n &amp;#39;r&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;!&amp;lt; echo -n &amp;#39;u&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;!&amp;lt; echo -n &amp;#39;n&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;send &amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sleep 0.1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# Terminate minicom when program completes (bit crazy..)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;expect &amp;#34;# &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sleep 0.1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;! killall -9 minicom
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s also worth talking about the end of this script. When minicom scripts end, the user is returned to an interactive session. I wanted the minicom process to terminate without clearing the screen, so I run &lt;code&gt;killall -9 minicom&lt;/code&gt; as the last line of the script.&lt;/p&gt;
&lt;p&gt;This is not the safest thing to include in a script, but it&amp;rsquo;s certainly effective, and I am quite certain that there is no built-in way to achieve this with the current version of minicom. Realistic alternatives include patching minicom, switching to different terminal software.&lt;/p&gt;
&lt;p&gt;The minicom invocation includes the name of the minicom script to execute, and the script will use the &lt;code&gt;TEST_PROGRAM&lt;/code&gt; environment variable to name the binary file to run.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;TEST_PROGRAM&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;test.bin minicom -b &lt;span class=&#34;m&#34;&gt;19200&lt;/span&gt; -S minicom_autorun.txt -D /dev/ttyUSB0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When running this command, the program executes on the 6502 computer seamlessly, though minicom leaves the terminal in a broken state when it is killed, and bash prints the &amp;ldquo;Killed&amp;rdquo; text to the screen.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer/2021-11-xmodem-test-04.png&#34;
	width=&#34;1702&#34;
	height=&#34;922&#34;
	srcset=&#34;https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer/2021-11-xmodem-test-04_hu_7eaec5c343f3aacf.png 480w, https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer/2021-11-xmodem-test-04_hu_4c4c87e0775f49c6.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;184&#34;
		data-flex-basis=&#34;443px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;To work around this, I wrapped the minicom invocation in a shell script which builds the program, suppresses all errors, and always returns 0. This avoids constant reporting that &lt;code&gt;killall -9&lt;/code&gt; is a problem, but it does hide any other problems.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -eu -o pipefail
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make &lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;.bin
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;TEST_PROGRAM&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;.bin minicom -b &lt;span class=&#34;m&#34;&gt;19200&lt;/span&gt; -S minicom_autorun.txt -D /dev/ttyUSB0 &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; 2&amp;gt; /dev/null
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This script is invoked as:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./assemble_and_run.sh &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer/2021-11-xmodem-test-05.png&#34;
	width=&#34;1702&#34;
	height=&#34;922&#34;
	srcset=&#34;https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer/2021-11-xmodem-test-05_hu_6d120e04185d50dd.png 480w, https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer/2021-11-xmodem-test-05_hu_f23d69c24aa55ae9.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;184&#34;
		data-flex-basis=&#34;443px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;A few months back, I &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-05-intellij-plugin-for-6502-assembly-language&#34; &gt;wrote an IntelliJ plugin&lt;/a&gt; for 6502 assembly, and I&amp;rsquo;m writing all of my code in PyCharm. The last step was to get this running from my IDE.&lt;/p&gt;
&lt;p&gt;I added a build configuration which invokes the &lt;code&gt;assemble_and_run.sh&lt;/code&gt; script. The script is completely generic, and I can use it to run other programs by changing the argument.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer/2021-11-6502-pycharm-01.png&#34;
	width=&#34;864&#34;
	height=&#34;640&#34;
	srcset=&#34;https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer/2021-11-6502-pycharm-01_hu_96dbfc65efc80b75.png 480w, https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer/2021-11-6502-pycharm-01_hu_df70a1f64c85437.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;135&#34;
		data-flex-basis=&#34;324px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I can now write a program, click run, and watch it execute on real hardware, all without leaving my IDE. It took a lot of effort, but this is a huge improvement from where I started.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer/2021-11-6502-pycharm-02.png&#34;
	width=&#34;1091&#34;
	height=&#34;807&#34;
	srcset=&#34;https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer/2021-11-6502-pycharm-02_hu_45bd1730a66bdc8b.png 480w, https://mike42.me/blog/2021-12-implementing-the-xmodem-protocol-for-file-transfer/2021-11-6502-pycharm-02_hu_98dac7fe2f797228.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;135&#34;
		data-flex-basis=&#34;324px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap-up
&lt;/h2&gt;&lt;p&gt;A fast compile/test/run cycle is a huge gain for developer productivity on any system. I can now get fast, accurate feedback on whether my 6502 assembly programs work on real hardware. The first program I&amp;rsquo;m writing involves interfacing with an SD card, which will be a lot more approachable with this improvement.&lt;/p&gt;
&lt;p&gt;I was surprised at how tricky it was to assemble and link a small program to run in RAM instead of ROM, and I can see that my linker configuration will need to be improved as I write programs which use more data. My basic plan is to test features by uploading them over XMODEM, then add them to the ROM when they are working.&lt;/p&gt;
&lt;p&gt;The full source code for this project, which includes hardware and software, can be found on GitHub at &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/6502-computer&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/6502-computer&lt;/a&gt;.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Designing a 3D printed enclosure for my KiCad project in Blender</title>
        <link>https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender</link>
        <pubDate>Thu, 18 Nov 2021 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender</guid>
        <description>&lt;p&gt;I recently &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb&#34; &gt;built a small 6502-based computer on a custom PCB&lt;/a&gt;, which I designed in KiCad. This blog post is about the process of building a 3D-printed case to house this project, using Blender.&lt;/p&gt;
&lt;p&gt;This is my first ever 3D print, so I had a few things to learn.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-01.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-01_hu_747924cc94ed2dc1.jpg 480w, https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-01_hu_207694e03b84f8a4.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;quick-background&#34;&gt;Quick background
&lt;/h2&gt;&lt;p&gt;My effort on this project has been focused on making a design which works, then transferring that design to a PCB. Since this is my first electronics project, I&amp;rsquo;m working sequentially, and have completely ignored the need for a case until now.&lt;/p&gt;
&lt;p&gt;I could have saved some time if I positioned the ports and mounting holes to match pre-made electronics enclosures, but I&amp;rsquo;ll take that as a lesson for my next project.&lt;/p&gt;
&lt;p&gt;The requirements for the enclosure are simple:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ability to mount the PCB inside the case&lt;/li&gt;
&lt;li&gt;Cut-out for power input&lt;/li&gt;
&lt;li&gt;Cut-outs for cable routing to expansion ports&lt;/li&gt;
&lt;li&gt;Cut-outs for power and reset buttons&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My PCB design files are in KiCad, and I decided to design the case in Blender, since I already know how to use it. Blender is not a CAD tool, but it is excellent for general-purpose 3D work, and will do just fine for this task.&lt;/p&gt;
&lt;h2 id=&#34;getting-scale&#34;&gt;Getting scale
&lt;/h2&gt;&lt;p&gt;My first challenge was to get the PCB into Blender at the correct scale, so that I could build a model around it. This is mostly just juggling file formats, but also note that Blender works in metres by default. I&amp;rsquo;ve set it to millimetres, with a scale of 0.001. There are &lt;a class=&#34;link&#34; href=&#34;https://blender.stackexchange.com/questions/153681/blender-2-8-units-of-scale-grid-and-default-size-of-objects/173140&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;guides on the web&lt;/a&gt; about how to set this.&lt;/p&gt;
&lt;p&gt;I tried two different methods.&lt;/p&gt;
&lt;h3 id=&#34;method-1-image-import&#34;&gt;Method 1: Image import
&lt;/h3&gt;&lt;p&gt;In KiCad, I added two &amp;ldquo;dimensions&amp;rdquo; to show the distance between the centre of the mounting holes, then plotted the front copper layer as an SVG.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-02.png&#34;
	width=&#34;2920&#34;
	height=&#34;1656&#34;
	srcset=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-02_hu_309ac7eb380baa95.png 480w, https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-02_hu_6307c9315277dd1d.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;176&#34;
		data-flex-basis=&#34;423px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I used Inkscape to convert from SVG to PNG. I then used GIMP to add cross-hairs to the centre of the mounting holes.&lt;/p&gt;
&lt;p&gt;In Blender, I added a single vertex at the origin, then extruded it on the X axis to match the measured dimension. I then added a reference image (the PNG file exported above), and scaled/moved the reference image until the cross-hairs lined up with the vertex.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-03.png&#34;
	width=&#34;3844&#34;
	height=&#34;2110&#34;
	srcset=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-03_hu_f38305bb03466ad1.png 480w, https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-03_hu_563a191ffdb33c41.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;182&#34;
		data-flex-basis=&#34;437px&#34;
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;method-2-model-import&#34;&gt;Method 2: Model import
&lt;/h3&gt;&lt;p&gt;KiCad can export its 3D model to a STEP file. I imported this file into FreeCAD, then exported it to STL.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-04.png&#34;
	width=&#34;3844&#34;
	height=&#34;2110&#34;
	srcset=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-04_hu_85131ff478e6109.png 480w, https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-04_hu_43b02afda0fa997d.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;182&#34;
		data-flex-basis=&#34;437px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Lastly, I imported the STL into Blender.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-05.png&#34;
	width=&#34;3844&#34;
	height=&#34;2110&#34;
	srcset=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-05_hu_998ebcc7f91e1a62.png 480w, https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-05_hu_f9f6eac8512d07e5.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;182&#34;
		data-flex-basis=&#34;437px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The scale is correct with both of these methods, because I can align the image and model.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-06.png&#34;
	width=&#34;3844&#34;
	height=&#34;2110&#34;
	srcset=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-06_hu_309627f2af326c71.png 480w, https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-06_hu_c4def38aaae20da.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;182&#34;
		data-flex-basis=&#34;437px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The second method produces much larger &lt;code&gt;.blend&lt;/code&gt; files, but has less room to make undetected errors, so I&amp;rsquo;ll be using it in the future.&lt;/p&gt;
&lt;h2 id=&#34;building-a-box&#34;&gt;Building a box
&lt;/h2&gt;&lt;p&gt;I modeled out the case as a lid and base with 3mm walls, and used boolean modifiers to cut out spaces for buttons and cables.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-07.png&#34;
	width=&#34;3844&#34;
	height=&#34;2110&#34;
	srcset=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-07_hu_af918979c61672f1.png 480w, https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-07_hu_70df414c1d297426.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;182&#34;
		data-flex-basis=&#34;437px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;One challenge was rounding the corners without the two pieces intersecting. I built the box as a square, then beveled it in wire-frame view. The spaces are larger than necessary, and I will try using modifiers slot the pieces together with a fixed tolerance if I need to do this again.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-08.png&#34;
	width=&#34;3840&#34;
	height=&#34;2106&#34;
	srcset=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-08_hu_37b26c5046efdec4.png 480w, https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-08_hu_ff3cb154cf53ec20.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;182&#34;
		data-flex-basis=&#34;437px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The result was two pieces which sit together but do not attach, with rounded corners and no sharp overhangs, for ease of manufacturing.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-animated.gif&#34;
	width=&#34;525&#34;
	height=&#34;355&#34;
	
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;147&#34;
		data-flex-basis=&#34;354px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;manufacturing-and-test&#34;&gt;Manufacturing and test
&lt;/h2&gt;&lt;p&gt;I exported the STL files, and sent them to a local manufacturer, since I don&amp;rsquo;t have my own 3D printer. The print is black PLA, printed with fused deposition modeling, with an 0.2mm layer height and 30% infill.&lt;/p&gt;
&lt;p&gt;When I received the parts, I first checked that the two pieces fitted together, then placed a blank PCB over the base to check that the holes lined up. PLA shrinks as it cools, but this aligned perfectly, which is either good luck or correct calibration.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-09.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-09_hu_e1b791f904aed88b.jpg 480w, https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-09_hu_51148fe56fb2fbec.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The computer&amp;rsquo;s board will be installed on standoffs, which are secured by a nut on the other side. I like the idea of using heat-set inserts instead, but I don&amp;rsquo;t want to try too many new things at once, so I&amp;rsquo;ve skipped the idea for now.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-10.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-10_hu_c2f5824c3209412c.jpg 480w, https://mike42.me/blog/2021-11-designing-a-3d-printed-enclosure-for-my-kicad-project-in-blender/2021-11-case-10_hu_84d72433b394ac8e.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next steps
&lt;/h2&gt;&lt;p&gt;At the time of writing, I&amp;rsquo;m still waiting for some parts to assemble this computer with a power/reset button, which will be the end of the hardware side of this project.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m quite happy with how this turned out as my first ever 3D print. If I need to make enclosures for future projects, I&amp;rsquo;ll take another look at open source parametric CAD tools such as OpenSCAD and FreeCAD, which are  more targeted to this kind of work.&lt;/p&gt;
&lt;p&gt;The STL files for this case are available on GitHub at &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/6502-computer&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/6502-computer&lt;/a&gt;, critique is welcome.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Building a hardware interrupt controller</title>
        <link>https://mike42.me/blog/2021-11-building-a-hardware-interrupt-controller</link>
        <pubDate>Thu, 04 Nov 2021 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2021-11-building-a-hardware-interrupt-controller</guid>
        <description>&lt;p&gt;I&amp;rsquo;ve recently been adding &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-10-re-creating-the-worlds-worst-sound-card&#34; &gt;simple hardware devices&lt;/a&gt; to my home-built &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb&#34; &gt;6502 computer&lt;/a&gt;, and ran into a problem.&lt;/p&gt;
&lt;p&gt;The 6502 has two active-low interrupt inputs (IRQ and NMI), both of which are used in my design. If I add any devices which can trigger their own interrupts, I will need a way to combine multiple interrupt signals into one.&lt;/p&gt;
&lt;h2 id=&#34;choosing-an-approach&#34;&gt;Choosing an approach
&lt;/h2&gt;&lt;p&gt;I researched some retro computer designs to see how this problem was handled, and found some very simple approaches.&lt;/p&gt;
&lt;p&gt;Most commonly, multiple I/O chips would be connected to the 6502&amp;rsquo;s IRQ line, which is level-triggered and active-low. As long as all connected chips had an &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Open_collector&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;open-drain&lt;/a&gt; IRQ output, they could be connected in a so-called wired-or configuration:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-11-building-a-hardware-interrupt-controller/2021-11-irq-wired.png&#34;
	width=&#34;356&#34;
	height=&#34;188&#34;
	srcset=&#34;https://mike42.me/blog/2021-11-building-a-hardware-interrupt-controller/2021-11-irq-wired_hu_ec2906854e5f4365.png 480w, https://mike42.me/blog/2021-11-building-a-hardware-interrupt-controller/2021-11-irq-wired_hu_b7d4698f08ae457c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;189&#34;
		data-flex-basis=&#34;454px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;In software, each interrupt source would be checked in priority order.&lt;/p&gt;
&lt;p&gt;I can&amp;rsquo;t use something so straightforward to add hardware to my design, for two main reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I would need to use logic gates to combine the inputs instead. The I/O chip which is connected to the CPU&amp;rsquo;s IRQ input at the moment is a WDC 65C22S, which does not have an open-drain IRQ output.&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s not going to be practical to check every I/O device from an interrupt service routine. I&amp;rsquo;m planning to add devices which are accessed over SPI, and will take many clock cycles to return their status.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Over in the PC world, programmable interrupt controllers such as the &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Intel_8259&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Intel 8259&lt;/a&gt; were used. Among other features, these chips combine multiple interrupt sources into one, and can report the interrupt source on the data bus.&lt;/p&gt;
&lt;p&gt;Rather than use out-of-production retro parts, I decided to program an ATF22V10 programmable logic device with these functions. A PLD is cheaper, and &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-10-programming-plds-with-open-source-software&#34; &gt;I&amp;rsquo;ve just figured out how to program them&lt;/a&gt;, so I might as well put those skills to use.&lt;/p&gt;
&lt;h2 id=&#34;creating-the-interrupt-controller&#34;&gt;Creating the interrupt controller
&lt;/h2&gt;&lt;p&gt;I am using &lt;a class=&#34;link&#34; href=&#34;https://github.com/simon-frankau/galette&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;galette&lt;/a&gt; to program these PLD&amp;rsquo;s, and went through 5 revisions of the PLD source file before landing on something which could complete these functions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;combine multiple interrupt lines into one.&lt;/li&gt;
&lt;li&gt;allow the CPU to quickly identify the highest-priority interrupt to service.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For this section, I&amp;rsquo;ll briefly describe each part of the PLD definition is doing.&lt;/p&gt;
&lt;p&gt;The file starts with the name of the target device, and a name for the chip.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;GAL22V10
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IrqController
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next pin definitions are listed. I&amp;rsquo;m using the ATF22V10, which has 24 pins. The first row is pins 1-12, while the second row is pins 13-24. Numbers go left-to-right in both rows, unlike a physical microchip!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Clock    /IRQ0 /IRQ1 IRQ2  /IRQ3 /IRQ4 IRQ5  /IRQ6 /IRQ7 /IRQ8 /IRQ9  GND
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/CS      D7    D6    D5    D4    D3    D2    D1    D0    /IRQ  /WE    VCC
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For combining the interrupts, I simply use a big OR function.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IRQ = IRQ0 + IRQ1 + IRQ2 + IRQ3 + IRQ4 + IRQ5 + IRQ6 + IRQ7 + IRQ8 + IRQ9
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This reads &amp;ldquo;IRQ is active if IRQ0 is active or IRQ1 is active or IRQ2 is active, etc.&amp;rdquo;. All logic is the positive case, so &amp;ldquo;IRQ0&amp;rdquo; means &amp;ldquo;IRQ0 is active&amp;rdquo;. Whether &amp;ldquo;active&amp;rdquo; means 1 or 0 at the input depends on those pin definitions. The active-low inputs are inverted before being fed to this expression, and the result will be inverted if the output is active-low. This confused me at first, because I thought that &amp;ldquo;/IRQ0&amp;rdquo; is just a pin name.&lt;/p&gt;
&lt;p&gt;The expressions for the data bus come next.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;These are all &amp;lsquo;registered&amp;rsquo; outputs (indicated with the &lt;code&gt;.R&lt;/code&gt; suffix). This runs the output through a D-type flip-flop, so that it will only change on clock transitions, rather than asynchronously. This is to avoid garbage output if an interrupt triggers while we are reading from the controller.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;D1..D4&lt;/code&gt; is a &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Priority_encoder&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;priority encoder&lt;/a&gt;, encoding the number 0 to 10 to identify the lowest-numbered interrupt source, or 11 if there is no interrupt.&lt;/li&gt;
&lt;li&gt;D0 is always 0. This &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Logical_shift&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;multiples the output by 2&lt;/a&gt;, which makes things easier for the software.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D0.R = GND
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D1.R = IRQ1*/IRQ0 + IRQ3*/IRQ2*/IRQ1*/IRQ0 + IRQ5*/IRQ4*/IRQ3*/IRQ2*/IRQ1*/IRQ0 + IRQ7*/IRQ6*/IRQ5*/IRQ4*/IRQ3*/IRQ2*/IRQ1*/IRQ0 + IRQ9*/IRQ8*/IRQ7*/IRQ6*/IRQ5*/IRQ4*/IRQ3*/IRQ2*/IRQ1*/IRQ0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D2.R = IRQ2*/IRQ1*/IRQ0 + IRQ3*/IRQ2*/IRQ1*/IRQ0 + IRQ6*/IRQ5*/IRQ4*/IRQ3*/IRQ2*/IRQ1*/IRQ0 + IRQ7*/IRQ6*/IRQ5*/IRQ4*/IRQ3*/IRQ2*/IRQ1*/IRQ0 + /IRQ9*/IRQ8*/IRQ7*/IRQ6*/IRQ5*/IRQ4*/IRQ3*/IRQ2*/IRQ1*/IRQ0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D3.R = IRQ4*/IRQ3*/IRQ2*/IRQ1*/IRQ0 + IRQ5*/IRQ4*/IRQ3*/IRQ2*/IRQ1*/IRQ0 + IRQ6*/IRQ5*/IRQ4*/IRQ3*/IRQ2*/IRQ1*/IRQ0 + IRQ7*/IRQ6*/IRQ5*/IRQ4*/IRQ3*/IRQ2*/IRQ1*/IRQ0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D4.R = /IRQ7*/IRQ6*/IRQ5*/IRQ4*/IRQ3*/IRQ2*/IRQ1*/IRQ0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D5.R = GND
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D6.R = GND
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D7.R = GND
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For the 22V10, not all pins support the same number of &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Product_term&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;product terms&lt;/a&gt;. As I built up to 10 interrupt sources, I needed to re-arrange the pins a few times.&lt;/p&gt;
&lt;p&gt;Lastly, I needed to tri-state the output when the chip was not being read. This is a second definition for each pin (&lt;code&gt;.E&lt;/code&gt; suffix). I used both a chip select (&lt;code&gt;/CS&lt;/code&gt;) and write enable (&lt;code&gt;/WE&lt;/code&gt;) input. The interrupt controller cannot be written to, this just allows me to avoid bus contention if somebody is attempting to.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D0.E = CS*/WE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D1.E = CS*/WE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D2.E = CS*/WE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D3.E = CS*/WE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D4.E = CS*/WE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D5.E = CS*/WE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D6.E = CS*/WE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D7.E = CS*/WE
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;test-circuit-and-software&#34;&gt;Test circuit and software
&lt;/h2&gt;&lt;p&gt;After testing everything on breadboard, I connected the new interrupt controller to my 6502 computer. All of the required signals are exposed via pin headers on my 6502 computer, more information about that can be found on &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb&#34; &gt;previous blog posts&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-11-building-a-hardware-interrupt-controller/2021-11-irq-controller-test.png&#34;
	width=&#34;1036&#34;
	height=&#34;795&#34;
	srcset=&#34;https://mike42.me/blog/2021-11-building-a-hardware-interrupt-controller/2021-11-irq-controller-test_hu_74c69863a82e2453.png 480w, https://mike42.me/blog/2021-11-building-a-hardware-interrupt-controller/2021-11-irq-controller-test_hu_e3460301eee4d56.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;130&#34;
		data-flex-basis=&#34;312px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This is how it looks. It&amp;rsquo;s not the neatest, but at least I don&amp;rsquo;t have &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer&#34; &gt;the whole computer&lt;/a&gt; on breadboards anymore.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-11-building-a-hardware-interrupt-controller/2021-11-irq-photo.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-11-building-a-hardware-interrupt-controller/2021-11-irq-photo_hu_71a27b720901c9f4.jpg 480w, https://mike42.me/blog/2021-11-building-a-hardware-interrupt-controller/2021-11-irq-photo_hu_bfe25ebd78773edb.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I then started writing some 6502 assembly code to test this out. I&amp;rsquo;ve been working on a shell which runs named commands, so I added a command called &lt;code&gt;irqtest&lt;/code&gt;. This code references other parts of the ROM, which can be found &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/6502-computer&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;in the GitHub repository for this project&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This code sets up a timer to trigger an interrupt on the 65C22 VIA, then uses the &lt;code&gt;wai&lt;/code&gt; instruction to wait for interrupts. When the interrupt service routine completes, the code resumes. I&amp;rsquo;ve assigned two addresses (&lt;code&gt;DEBUG_LAST_INTERRUPT_INDEX&lt;/code&gt; and &lt;code&gt;DEBUG_INTERRUPT_COUNT&lt;/code&gt;) so that we can check that the correct interrupt routines are running.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Set up a timer to trigger an IRQ
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;IRQ_CONTROLLER&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$8C00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Some values to help us debug
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;DEBUG_LAST_INTERRUPT_INDEX&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;DEBUG_INTERRUPT_COUNT&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$01&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;shell_irqtest_main:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$ff              ; set interrupt index to dummy value (so we can see if it&amp;#39;s not being overridden)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;DEBUG_LAST_INTERRUPT_INDEX&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$00              ; reset interrupt counter
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$01&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;; setup for via
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%00000000        ; set ACR. first two bits = 00 is one-shot for T1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;VIA_ACR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%11000000        ; enable VIA interrupt for T1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;VIA_IER&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;sei&lt;/span&gt;                   &lt;span class=&#34;c1&#34;&gt;; enable IRQ at CPU - normally off in this code
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;; set up a timer at ~65535 clock pulses.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$ff              ; set T1 low-order counter
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;VIA_T1C_L&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$ff              ; set T1 high-order counter
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;VIA_T1C_H&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;wai&lt;/span&gt;                   &lt;span class=&#34;c1&#34;&gt;; wait for interrupt
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;; reset for via
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;cli&lt;/span&gt;                   &lt;span class=&#34;c1&#34;&gt;; disable IRQ at CPU - normally off in this code
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#%01000000        ; disable VIA interrupt for T1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;; Print out which interrupt was used, should be 02 if irq1_isr ran
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;DEBUG_LAST_INTERRUPT_INDEX&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;hex_print_byte&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;shell_newline&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;; print number of times interrupt ran, should be 01 if it only ran once
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;DEBUG_INTERRUPT_COUNT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;hex_print_byte&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;shell_newline&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;sys_exit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I set my interrupt service routine read from the interrupt controller, then jump to the correct routine.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;irq:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;phx&lt;/span&gt;                       &lt;span class=&#34;c1&#34;&gt;; push x for later
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;inc&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;DEBUG_INTERRUPT_COUNT&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;; count how many times this runs..
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;IRQ_CONTROLLER&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;; read interrupt controller to find highest-priority interrupt to service
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;isr_jump_table&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;X&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;   &lt;span class=&#34;c1&#34;&gt;; jump to matching service routine
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;irq_return:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;plx&lt;/span&gt;                       &lt;span class=&#34;c1&#34;&gt;; restore x
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;rti&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The interrupt controller can return 11 possible values, so I made an 11-entry table, with the address for each interrupt handler (2 bytes each). I have connected the VIA to &lt;code&gt;IRQ1&lt;/code&gt;, so I set the second entry to a subroutine called &lt;code&gt;irq1_isr&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;isr_jump_table:&lt;/span&gt;              &lt;span class=&#34;c1&#34;&gt;; 10 possible interrupt sources
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nop_isr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;irq1_isr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nop_isr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nop_isr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nop_isr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nop_isr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nop_isr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nop_isr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nop_isr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nop_isr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.word&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;nop_isr&lt;/span&gt;               &lt;span class=&#34;c1&#34;&gt;; 11th option for when no source is triggering the interrupt (phantom interrupt)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Most of the interrupt routines map to nothing at all. If this were a real OS, an interrupt from an unknown source would need to be a fatal error, since it can&amp;rsquo;t be individually masked/ignored on this hardware.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;nop_isr:&lt;/span&gt;                         &lt;span class=&#34;c1&#34;&gt;; interrupt routine for anything else
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;stx&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;DEBUG_LAST_INTERRUPT_INDEX&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;; store interrupt index for debugging
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;irq_return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When &lt;code&gt;IRQ1&lt;/code&gt; is triggered though, this routine will clear the interrupt on the VIA. If we fail to do this, then the CPU will become stuck, processing interrupts forever.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;irq1_isr:&lt;/span&gt;                        &lt;span class=&#34;c1&#34;&gt;; interrupt routine for VIA
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;stx&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;DEBUG_LAST_INTERRUPT_INDEX&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;; store interrupt index for debugging
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;VIA_T1C_L&lt;/span&gt;                  &lt;span class=&#34;c1&#34;&gt;; clear IFR bit 6 on VIA (side-effect of reading T1 low-order counter)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;jmp&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;irq_return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once I fixed some bugs, I was able to get the expected output, which is &lt;code&gt;02&lt;/code&gt; (the index we are using to jump into &lt;code&gt;isr_jump_table&lt;/code&gt;), followed by &lt;code&gt;01&lt;/code&gt; (the number of times the interrupt service routine runs).&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-11-building-a-hardware-interrupt-controller/2021-11-irq-screenshot.png&#34;
	width=&#34;1572&#34;
	height=&#34;1066&#34;
	srcset=&#34;https://mike42.me/blog/2021-11-building-a-hardware-interrupt-controller/2021-11-irq-screenshot_hu_b3f760642f4a8282.png 480w, https://mike42.me/blog/2021-11-building-a-hardware-interrupt-controller/2021-11-irq-screenshot_hu_2bb3c315c3a3cbbd.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;147&#34;
		data-flex-basis=&#34;353px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;While I was researching this, I also found that online 6502 assembly guides often suggest clearing the interrupt flag on I/O chips near the start of the interrupt service routine, apparently to avoid running the routine twice. From this test, I know that the interrupt service routine is only running once, so I am happily disregarding that advice. Thinking about it, I can only see this applying to open-drain IRQ outputs.&lt;/p&gt;
&lt;h2 id=&#34;note-about-kicad-symbols&#34;&gt;Note about KiCad symbols
&lt;/h2&gt;&lt;p&gt;Since my last blog post about PLD&amp;rsquo;s, I&amp;rsquo;ve started to create separate symbols in KiCad for each programmed chip. You can see one of these in the schematic above.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m producing these automatically. Galette has a &lt;code&gt;.pin&lt;/code&gt; file as one of its outputs. The file for this chip is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; Pin # | Name     | Pin Type
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-----------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   1   | Clock    | Clock/Input
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   2   | /IRQ0    | Input
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   3   | /IRQ1    | Input
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   4   | IRQ2     | Input
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   5   | /IRQ3    | Input
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   6   | /IRQ4    | Input
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   7   | IRQ5     | Input
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   8   | /IRQ6    | Input
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   9   | /IRQ7    | Input
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  10   | /IRQ8    | Input
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  11   | /IRQ9    | Input
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  12   | GND      | GND
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  13   | /CS      | Input
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  14   | D7       | Output
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  15   | D6       | Output
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  16   | D5       | Output
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  17   | D4       | Output
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  18   | D3       | Output
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  19   | D2       | Output
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  20   | D1       | Output
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  21   | D0       | Output
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  22   | /IRQ     | Output
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  23   | /WE      | Input
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  24   | VCC      | VCC
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To produce schematic symbols, I wrote a small Python script to convert this text format to a CSV file, suitable for &lt;a class=&#34;link&#34; href=&#34;https://github.com/devbisme/KiPart&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;KiPart&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IRQ_Controller
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Pin,Type,Name
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;1,input,Clock
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2,input,~IRQ0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;3,input,~IRQ1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;4,input,IRQ2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;5,input,~IRQ3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;6,input,~IRQ4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;7,input,IRQ5
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;8,input,~IRQ6
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;9,input,~IRQ7
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;10,input,~IRQ8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;11,input,~IRQ9
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;12,power_in,GND
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;13,input,~CS
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;14,output,D7
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;15,output,D6
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;16,output,D5
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;17,output,D4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;18,output,D3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;19,output,D2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;20,output,D1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;21,output,D0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;22,output,~IRQ
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;23,input,~WE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;24,power_in,VCC
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;KiPart ships with profiles for FPGA chips, but the &lt;code&gt;generic&lt;/code&gt; input worked fine for the ATF22V10 PLD.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./KiPart/venv/bin/kipart -r generic --overwrite irq_controller.csv
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The output is a &lt;code&gt;.lib&lt;/code&gt; file, which I can include in any KiCad project.&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap-up
&lt;/h2&gt;&lt;p&gt;This approach works, and introduces far less overhead compared with checking each device in the interrupt service routine. In particular, it will allow me to test interrupts from slow-to-access SPI devices.&lt;/p&gt;
&lt;p&gt;I will be disconnecting this this for now, but may include it in an expansion board or updated computer design if I ever make one!&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Programming PLD&#39;s with open source software</title>
        <link>https://mike42.me/blog/2021-10-programming-plds-with-open-source-software</link>
        <pubDate>Thu, 21 Oct 2021 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2021-10-programming-plds-with-open-source-software</guid>
        <description>&lt;p&gt;A few weeks ago, I blogged about &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic&#34; &gt;my setup&lt;/a&gt; for programming PLD&amp;rsquo;s from Linux, which are the simpler ancestors of modern FPGA&amp;rsquo;s.&lt;/p&gt;
&lt;p&gt;The device I&amp;rsquo;m using is the ATF22V10, and programming it in involved running decades-old proprietary software called WinCUPL under WINE. I recently found an opportinity to test-run an open-source alternative, &lt;a class=&#34;link&#34; href=&#34;https://github.com/simon-frankau/galette&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;galette&lt;/a&gt;, and this blog post is a few notes about how it went.&lt;/p&gt;
&lt;h2 id=&#34;re-visiting-my-assumptions&#34;&gt;Re-visiting my assumptions
&lt;/h2&gt;&lt;p&gt;The Atmel ATF22V10 is pin-compatible with the Lattice &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/GAL22V10&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;GAL22V10&lt;/a&gt;, which was discontinued over 10 years ago. There is a lot more information and software available for Lattice GAL&amp;rsquo;s, which I assume had the mind-share back when these devices were relevant.&lt;/p&gt;
&lt;p&gt;There are some slight differences between the Atmel and Lattice devices. Some programming hardware works with one but not the other, and I had assumed that the fuse map (JED file) would be incompatible as well. This turned out to be incorrect.&lt;/p&gt;
&lt;p&gt;A few statements online made me look at this again &amp;ldquo;You can also write Lattice GAL maps to the Atmel ATF16V8 and 22V10 parts&amp;rdquo; (&lt;a class=&#34;link&#34; href=&#34;https://www.retrobrewcomputers.org/forum/index.php?t=msg&amp;amp;th=335&amp;amp;#msg_5408&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Andrew B on retrobrewcomputers.org&lt;/a&gt;), and &amp;ldquo;The most suitable replacement for the GAL22V10 from Atmel is the ATF22V10C/CQ/CQZ. They are pin-to-pin and JEDEC fusemap compatible.&amp;rdquo; (&lt;a class=&#34;link&#34; href=&#34;https://microchipsupport.force.com/s/article/GAL22V10-replacement&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;GAL22V10 replacement on the Microchip knowledgebase&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The open source tool &lt;a class=&#34;link&#34; href=&#34;https://github.com/simon-frankau/galette&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;galette&lt;/a&gt; can create JED files for the Lattice GAL22V10, so I decided to try to write its output to an ATF22V10 to see for myself.&lt;/p&gt;
&lt;h2 id=&#34;detour-installing-a-rust-toolchain&#34;&gt;Detour: Installing a Rust toolchain
&lt;/h2&gt;&lt;p&gt;Galette is written in Rust, and available only as source code at the time of writing. The instructions for setting up Rust are online &lt;a class=&#34;link&#34; href=&#34;https://www.rust-lang.org/tools/install&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt install curl
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;curl --proto &amp;#39;=https&amp;#39; --tlsv1.2 -sSf https://sh.rustup.rs | sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then to compile any Rust project is the same process:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cargo build
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;finding-an-example-jed-file&#34;&gt;Finding an example JED file
&lt;/h2&gt;&lt;p&gt;Next I tried running the tests, which did not pass&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ./run_tests.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I found that this was simply the assembler version being different, plus a trailing number (maybe a checksum?).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gh&#34;&gt;diff -ru baseline/vcc.jed test_tmp/vcc.jed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gh&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gd&#34;&gt;--- baseline/vcc.jed    2021-08-19 20:16:20.526847059 +1000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+++ test_tmp/vcc.jed    2021-08-19 20:26:00.367537520 +1000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gu&#34;&gt;@@ -1,5 +1,5 @@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gd&#34;&gt;-GAL-Assembler:  Galette 0.2.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+GAL-Assembler:  Galette 0.3.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gi&#34;&gt;&lt;/span&gt; Device:         GAL16V8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; *F0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;@@ -25,4 +25,4 @@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt; *L2193 0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; *C3c8f
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gd&#34;&gt;-924f
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gd&#34;&gt;&lt;/span&gt;&lt;span class=&#34;gi&#34;&gt;+9250
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I then took one of the test outputs, and tried writing it to a device. As detailed in &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic&#34; &gt;my earlier blog post&lt;/a&gt;, I&amp;rsquo;m using &lt;a class=&#34;link&#34; href=&#34;https://gitlab.com/DavidGriffith/minipro&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;minipro&lt;/a&gt;, with a TL866II+ programmer, which could only program these devices after a firmware update.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ minipro -p ATF22V10CQZ -w baseline/GAL22V10_combinatorial.jed
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Found TL866II+ 04.2.126 (0x27e)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Warning: Firmware is newer than expected.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Expected  04.2.123 (0x27b)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Found     04.2.126 (0x27e)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;VPP=12V
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Warning! JED file doesn&amp;#39;t match the selected device!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Declared fuse checksum: 0x87E2 Calculated: 0x87E2 ... OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Declared file checksum: 0x12CF Calculated: 0x12D0 ... Mismatch!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;JED file parsed OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Use -P to skip write protect
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Erasing... 0.33Sec OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Writing jedec file...  5.04Sec  OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Reading device...  0.41Sec  OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Writing lock bit... 0.36Sec OK
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With failed tests, checksum errors, firmware version mismatch and device ID mismatch, I was not expecting this to work.&lt;/p&gt;
&lt;p&gt;Checking the source for this file, one of the lines is a simple AND expression.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;O0 = I0 * I1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I wired up two inputs and one output (pins 2, 3 and 14), to confirm that it behaved as expected.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-10-programming-plds-with-open-source-software/2021-10-atf22v10-test-schematic.png&#34;
	width=&#34;577&#34;
	height=&#34;589&#34;
	srcset=&#34;https://mike42.me/blog/2021-10-programming-plds-with-open-source-software/2021-10-atf22v10-test-schematic_hu_6f452cdc6b9bcab0.png 480w, https://mike42.me/blog/2021-10-programming-plds-with-open-source-software/2021-10-atf22v10-test-schematic_hu_b8179e2cc945995c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;97&#34;
		data-flex-basis=&#34;235px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I used a multimeter to check that it was drawing a reasonably low current (about 7 mA). In &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic&#34; &gt;previous experiments&lt;/a&gt;, these chips had made a lot of heat when programmed incorrectly.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-10-programming-plds-with-open-source-software/2021-10-atf22v10-test.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-10-programming-plds-with-open-source-software/2021-10-atf22v10-test_hu_1d2588614ef8eef1.jpg 480w, https://mike42.me/blog/2021-10-programming-plds-with-open-source-software/2021-10-atf22v10-test_hu_5d9118545485121c.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Everything worked, so this open-source replacement is looking good so far.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: I repeated the simple test of combinatorial logic in an ATF22LV10C running at 3.3v. At the time of writing, this &amp;rsquo;low voltage&amp;rsquo; variant is not listed as a supported chip in minipro, but can be programmed using the exact same procedure as an ATF22V10, and then operated at either 5V or 3.3V. The command I am using to program this chip is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;minipro -p ATF22V10CQZ -w baseline/GAL22V10_combinatorial.jed
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;interfacing-with-a-6502-computer&#34;&gt;Interfacing with a 6502 computer
&lt;/h2&gt;&lt;p&gt;I have some ideas for using programmable logic to extend my &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb&#34; &gt;6502-based computer&lt;/a&gt;, so I wanted to test tri-state output.&lt;/p&gt;
&lt;p&gt;The previous test only used combinatorial output, where each pin is set high or low according to a logic function. For the ATF22V10, it should also possible to program an &amp;ldquo;output enable&amp;rdquo; function for each pin, in order to use &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Three-state_logic&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;tri-state logic&lt;/a&gt;. This would allow me to connect it to the 8-bit data bus on my home-built computer.&lt;/p&gt;
&lt;p&gt;The best documentation for this was:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/daveho/GALasm/blob/master/galer/gal22v10.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;The galer documentation for the GAL22V10&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/simon-frankau/galette/blob/master/testcases/GAL16V8_tri.pld&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;The GAL16V8_tri.pld example in Galette&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To test this, I programmed an ATF22V10 to output &amp;ldquo;42&amp;rdquo; (0010 1010) to the data bus when an output enable pin is low. In the source file, 0 is &lt;code&gt;GND&lt;/code&gt;, and 1 is &lt;code&gt;VCC&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Tri-state outputs are suffixed with &lt;code&gt;.T&lt;/code&gt;, while outputs suffixed with &lt;code&gt;.E&lt;/code&gt; are the &amp;ldquo;output enable&amp;rdquo; functions for that pin (the pin is high-impedance when false). I left one output in the combinatorial mode (always enabled), to verify that this is being controlled separately for each pin.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;GAL22V10
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Test1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;NC    NC    I1    OE    NC    NC    NC    NC    NC    NC    NC   GND
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;NC    NC    O1    D7    D6    D5    D4    D3    D2    D1    D0   VCC
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;O1 = I1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D0.T = GND
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D1.T = VCC
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D2.T = GND
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D3.T = VCC
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D4.T = GND
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D5.T = VCC
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D6.T = GND
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D7.T = GND
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D0.E = /OE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D1.E = /OE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D2.E = /OE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D3.E = /OE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D4.E = /OE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D5.E = /OE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D6.E = /OE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D7.E = /OE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;DESCRIPTION
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Output 42 on the data bus when output is enabled.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I used my local build of Galette to generate a JED file, then wrote the JED file to the chip using the same process as before.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ./galette/target/debug/galette test1.pld
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ minipro -p ATF22V10CQZ -w test1.jed
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I then built this test circuit, which connects one I/O select line from my computer to the PLD, plus the 8-bit data bus. The combinatorial output is connected to an LED for testing.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-10-programming-plds-with-open-source-software/2021-10-atf22v10-peripheral-schematic.png&#34;
	width=&#34;765&#34;
	height=&#34;609&#34;
	srcset=&#34;https://mike42.me/blog/2021-10-programming-plds-with-open-source-software/2021-10-atf22v10-peripheral-schematic_hu_b91c342f0ebb19c2.png 480w, https://mike42.me/blog/2021-10-programming-plds-with-open-source-software/2021-10-atf22v10-peripheral-schematic_hu_fea941fa2b30f322.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;125&#34;
		data-flex-basis=&#34;301px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;IO2&lt;/code&gt; input maps to address &lt;code&gt;$8800&lt;/code&gt; in &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer&#34; &gt;my computer&amp;rsquo;s address decoding scheme&lt;/a&gt;. I have other blog posts about &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-10-re-creating-the-worlds-worst-sound-card&#34; &gt;mapping new hardware devices into memory&lt;/a&gt; if you&amp;rsquo;re interested to know how that works.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-10-programming-plds-with-open-source-software/2021-10-atf22v10-peripheral-breadboard.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-10-programming-plds-with-open-source-software/2021-10-atf22v10-peripheral-breadboard_hu_cbc03150b2f9bd78.jpg 480w, https://mike42.me/blog/2021-10-programming-plds-with-open-source-software/2021-10-atf22v10-peripheral-breadboard_hu_aa8ca3712d1d5000.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This computer boots to BASIC, and I was able to print &amp;ldquo;42&amp;rdquo; by reading this memory address via the &lt;code&gt;PEEK&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-10-programming-plds-with-open-source-software/2021-10-atf22v10-peripheral-test.png&#34;
	width=&#34;1572&#34;
	height=&#34;958&#34;
	srcset=&#34;https://mike42.me/blog/2021-10-programming-plds-with-open-source-software/2021-10-atf22v10-peripheral-test_hu_6a9c83b3ba2e9f8f.png 480w, https://mike42.me/blog/2021-10-programming-plds-with-open-source-software/2021-10-atf22v10-peripheral-test_hu_e4e6f236f3408ff2.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;164&#34;
		data-flex-basis=&#34;393px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This also confirms that D0 is the least-significant bit in the data bus, which I was not sure of before.&lt;/p&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next steps
&lt;/h2&gt;&lt;p&gt;This has been an interesting discovery for me, and I&amp;rsquo;m planning to use Galette instead of WinCUPL for my electronics projects. PLD&amp;rsquo;s are relatively obscure, and it&amp;rsquo;s great to have an open-source tool for working with them. The only thing I will miss from WinCUPL it its test/simulation feature. I now need to program a chip and test it in a circuit, which is laborious, and I&amp;rsquo;m quickly using up the  limited number of write cycles that these devices are rated for.&lt;/p&gt;
&lt;p&gt;I created an &amp;ldquo;ATF22V10&amp;rdquo; symbol in KiCad to draw the schematics for this blog post, which is not particularly clear, since the pin names do not correspond with the ones defined in the &lt;code&gt;.pld&lt;/code&gt; file. The next time I&amp;rsquo;m including one of these in a schematic, I&amp;rsquo;ll try creating a separate symbol for each programmed chip.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m planning to use an ATF22V10 PLD to build an interrupt controller for my computer, look out for a future blog post about that.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Re-creating the world&#39;s worst sound card</title>
        <link>https://mike42.me/blog/2021-10-re-creating-the-worlds-worst-sound-card</link>
        <pubDate>Thu, 07 Oct 2021 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2021-10-re-creating-the-worlds-worst-sound-card</guid>
        <description>&lt;p&gt;I recently &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb&#34; &gt;built a computer from scratch&lt;/a&gt;, and wanted to add some basic sound output. I am not attempting to produce any 8-bit music, but I would like to be able to write programs use beeps and clicks to provide feedback, instead of only text.&lt;/p&gt;
&lt;p&gt;I did a bit of digging into the subject, and found quite possibly the world&amp;rsquo;s worst sound card, in the Apple II. This is my attempt to re-draw the relevant part of the schematic, which I found in a 1983 publication called &lt;a class=&#34;link&#34; href=&#34;https://archive.org/details/apple-ii-circuit-description/page/n3/mode/2up&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;The Apple II Circuit Description&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-10-re-creating-the-worlds-worst-sound-card/2021-10-sound-schematic-1.png&#34;
	width=&#34;1090&#34;
	height=&#34;391&#34;
	srcset=&#34;https://mike42.me/blog/2021-10-re-creating-the-worlds-worst-sound-card/2021-10-sound-schematic-1_hu_a0a4296e73900cfd.png 480w, https://mike42.me/blog/2021-10-re-creating-the-worlds-worst-sound-card/2021-10-sound-schematic-1_hu_6672589599b3a400.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;278&#34;
		data-flex-basis=&#34;669px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The linked book does a good job of explaining the details, but the important part for this blog post is simply that &lt;code&gt;Z3&lt;/code&gt; is an address decoding output. It is normally high, but is low for half a cycle each time that memory address &lt;code&gt;$C030&lt;/code&gt; is accessed. This is fed to a flip-flop, which will toggle each time this happens, driving a speaker.&lt;/p&gt;
&lt;p&gt;This should be easy for me to implement, since I have spare address decoding outputs on my computer.&lt;/p&gt;
&lt;h2 id=&#34;first-attempt&#34;&gt;First attempt
&lt;/h2&gt;&lt;p&gt;I decided to use a piezo buzzer, which can be driven directly from an IC pin, simplifying things greatly.&lt;/p&gt;
&lt;p&gt;I first connected the buzzer directly to one of the spare address decoding outputs of my computer.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-10-re-creating-the-worlds-worst-sound-card/2021-10-sound-build-2.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-10-re-creating-the-worlds-worst-sound-card/2021-10-sound-build-2_hu_dad1033c8726fc1a.jpg 480w, https://mike42.me/blog/2021-10-re-creating-the-worlds-worst-sound-card/2021-10-sound-build-2_hu_279b3a794ea89211.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This is so simple that it is almost not worth diagramming, but here goes:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-10-re-creating-the-worlds-worst-sound-card/2021-10-sound-schematic-2.png&#34;
	width=&#34;381&#34;
	height=&#34;152&#34;
	srcset=&#34;https://mike42.me/blog/2021-10-re-creating-the-worlds-worst-sound-card/2021-10-sound-schematic-2_hu_dd15ca4a89053ffa.png 480w, https://mike42.me/blog/2021-10-re-creating-the-worlds-worst-sound-card/2021-10-sound-schematic-2_hu_f53ee87eefed2b10.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;250&#34;
		data-flex-basis=&#34;601px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The input is &lt;code&gt;IO2&lt;/code&gt;, which works out to address &lt;code&gt;$8800&lt;/code&gt; in my computer&amp;rsquo;s memory map. I wrote a bit about in &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer&#34; &gt;an earlier blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;From BASIC (yes, this computer &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-09-porting-basic-to-my-6502-computer&#34; &gt;runs BASIC&lt;/a&gt;), I can read from this address and produce a click.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;A=PEEK($8800)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;second-attempt&#34;&gt;Second attempt
&lt;/h2&gt;&lt;p&gt;To produce a beep, I wanted a square wave with a 50% duty cycle. The Apple II used a 74LS74 dual D flip flop IC for this, which I don&amp;rsquo;t have in my inventory. Instead, I used a 74AC163 4-bit counter.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-10-re-creating-the-worlds-worst-sound-card/2021-10-sound-build-3.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-10-re-creating-the-worlds-worst-sound-card/2021-10-sound-build-3_hu_a4c833250734e2a.jpg 480w, https://mike42.me/blog/2021-10-re-creating-the-worlds-worst-sound-card/2021-10-sound-build-3_hu_6eade669f21ab8bf.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The circuit on the breadboard is wired up like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-10-re-creating-the-worlds-worst-sound-card/2021-10-sound-schematic-3.png&#34;
	width=&#34;743&#34;
	height=&#34;570&#34;
	srcset=&#34;https://mike42.me/blog/2021-10-re-creating-the-worlds-worst-sound-card/2021-10-sound-schematic-3_hu_fe83d09548806d90.png 480w, https://mike42.me/blog/2021-10-re-creating-the-worlds-worst-sound-card/2021-10-sound-schematic-3_hu_d0f72c7bb4cc5006.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;130&#34;
		data-flex-basis=&#34;312px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I was then able to produce a beeping sound by reading a memory address in a loop, just as you could on the Apple II.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;10 A=PEEK($8800)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;20 GOTO 10
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;RUN
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Mission accomplished.&lt;/p&gt;
&lt;h2 id=&#34;alternatives-and-next-steps&#34;&gt;Alternatives and next steps
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;ve already started adding clicks and beeps to assembly code while testing, and my immediate plan is to add a separate startup beep for each of the two boot ROMs. If I ever do a second revision of this computer board, I&amp;rsquo;ll most likely add a speaker as an on-board peripheral, using a 74LS74 instead of the counter.&lt;/p&gt;
&lt;p&gt;There are two other methods which considered for adding beeps to this computer. The first was to utilise its 65C22 chip, which can be set to output a square wave on its &lt;code&gt;PB7&lt;/code&gt; pin. I have other plans for that output, which is the reason I haven&amp;rsquo;t used it for sound.&lt;/p&gt;
&lt;p&gt;The second idea I looked into was sampled audio, which would require me to latch 8-bit audio samples a few thousand times per second, and then use some resistors to build a digital-to-analog converter. There are a few ways that I could achieve this with parts which I have on-hand, such as a SN74AC573 latch, or the 65C22.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>6502 computer - from breadboard to PCB</title>
        <link>https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb</link>
        <pubDate>Thu, 23 Sep 2021 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb</guid>
        <description>&lt;p&gt;I&amp;rsquo;ve recently been working on building a 6502-based computer on breadboards as a learning project. After making &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer&#34; &gt;a few revisions&lt;/a&gt;, and &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-09-porting-basic-to-my-6502-computer&#34; &gt;porting some software&lt;/a&gt; to run on it, I was confident that my computer worked well enough to connect up permanently on a circuit board.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-pcb-01.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-pcb-01_hu_2193a83e7d76c09.jpg 480w, https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-pcb-01_hu_441d7bd6fb452559.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This blog post about the process that I went through to convert my working breadboard prototype to a PCB. As somebody who is not trained in electronics, this involved some fresh challenges for me.&lt;/p&gt;
&lt;h2 id=&#34;schematic-capture&#34;&gt;Schematic capture
&lt;/h2&gt;&lt;p&gt;As a first step, I needed to draw up a proper schematic in a CAD tool. I&amp;rsquo;ve already been learning to use KiCad&amp;rsquo;s Eeschema for schematic capture, so I went ahead and drew up the whole thing.&lt;/p&gt;
&lt;p&gt;I decided to put all of the components on one crowded page, just because I haven&amp;rsquo;t learned to manage multiple pages yet.&lt;/p&gt;
&lt;p&gt;&lt;div class=&#34;img-canvas-outer&#34;&gt;
&lt;a href=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-schematic.svg&#34; class=&#34;img-canvas-link  &#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-schematic.svg&#34;
	
	
	
	loading=&#34;lazy&#34;
	
	
	    class=&#34;img-canvas-inner&#34; 
	
&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Mostly, this was just replicating what I&amp;rsquo;d already built, but I also needed to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;create a symbol for the DS-1813, which I could not find in the libraries I&amp;rsquo;m using&lt;/li&gt;
&lt;li&gt;decide on a pinout for expansion ports&lt;/li&gt;
&lt;li&gt;add a jumper block, so that the two interrupt lines (NMI and IRQ) can be disconnected from the on-board chips&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I avoided changing the scope of the board to include important features (storage, audio), and instead added a header with all of the important buses and signals. My goal is to have a stable base system to work with, and I can always do a second board once I&amp;rsquo;ve figured out how these should work.&lt;/p&gt;
&lt;p&gt;I did not use KiCad&amp;rsquo;s inbuilt BOM plugins, but instead manually wrote a parts list for future reference. The only components which I needed to order were sockets and pin headers, everything else was being lifted from the prototype.&lt;/p&gt;
&lt;h2 id=&#34;footprint-assignment&#34;&gt;Footprint assignment
&lt;/h2&gt;&lt;p&gt;Once the Eeschema electrical rules check was passing, I moved on to selecting footprints for everything. I spent quite a bit of time checking the datasheets for my planned components against the KiCad library to choose footprints that would fit.&lt;/p&gt;
&lt;p&gt;I could not find anything which matched the footprint of the mini SPDT switches that I&amp;rsquo;m using, so I made my own.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-spdt-footprint.png&#34;
	width=&#34;2904&#34;
	height=&#34;1598&#34;
	srcset=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-spdt-footprint_hu_3a039a3443922b12.png 480w, https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-spdt-footprint_hu_d68fcaef9bb412da.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;181&#34;
		data-flex-basis=&#34;436px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I had not yet chosen a ZIF socket for the EEPROM, so I selected a footprint for a standard socket instead. This was a risky move, because I had to guess how much space to leave when laying out the board.&lt;/p&gt;
&lt;h2 id=&#34;pcb-design&#34;&gt;PCB design
&lt;/h2&gt;&lt;p&gt;I had already selected a board manufacturer, so I set up my track widths and via sizes according to their capabilities.&lt;/p&gt;
&lt;p&gt;Next, I imported the netlist and placed the components. I attempted to fit everything in 10cm x 10cm, 2-layer board to save on manufacturing costs, but it was &lt;em&gt;very&lt;/em&gt; crowded. I was worried about having enough space for traces, fitting an (unmeasured) ZIF socket, and adding some mounting holes, so I spaced it out to fit on a 10cm x 11.6cm board instead.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-placement.png&#34;
	width=&#34;3844&#34;
	height=&#34;2110&#34;
	srcset=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-placement_hu_75d60ed7ddbd71b1.png 480w, https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-placement_hu_ab7421748229630.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;182&#34;
		data-flex-basis=&#34;437px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I also added footprints for M3-sized mounting holes, and edge cuts with rounded corners.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-edge-cuts.png&#34;
	width=&#34;2920&#34;
	height=&#34;1614&#34;
	srcset=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-edge-cuts_hu_f6c6f472760320f0.png 480w, https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-edge-cuts_hu_47bedeb92de4b1ce.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;180&#34;
		data-flex-basis=&#34;434px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;It took me 4 attempts to successfully route all of the traces. The result breaks every PCB layout best practice which I had read about, but I was happy just to have everything connected by that point.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-layout.png&#34;
	width=&#34;3844&#34;
	height=&#34;2110&#34;
	srcset=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-layout_hu_2af68b1a86dddfcd.png 480w, https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-layout_hu_42de2247d1e5640b.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;182&#34;
		data-flex-basis=&#34;437px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;In hindsight, I could have made this task easier by splitting up the expansion header, and building an accurate footprint for a ZIF socket. I also could have placed the decoupling capacitors closer to the IC power pins, and avoided interrupting the ground plane.&lt;/p&gt;
&lt;p&gt;The silkscreen setup was more time-consuming than expected. I wanted to make the board as self-documenting as possible, so that I would not need to open the design files on a computer when writing code and adding hardware peripherals. I labelled every switch, button, light and IC, as well as every expansion header pin (74 of them!). I also added some simple assembly hints such as resistor values, and +/- signs to indicate the polarity of the lone electrolytic capacitor.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-silkscreen.png&#34;
	width=&#34;3844&#34;
	height=&#34;2110&#34;
	srcset=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-silkscreen_hu_9e35d5619f86d21f.png 480w, https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-silkscreen_hu_ccd599477e6b3381.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;182&#34;
		data-flex-basis=&#34;437px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The 3D render view in KiCad shows how the finished board would look.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-pcb-view-01.png&#34;
	width=&#34;3844&#34;
	height=&#34;2164&#34;
	srcset=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-pcb-view-01_hu_66f47ed57739231e.png 480w, https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-pcb-view-01_hu_b030cca052a159fd.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Components did not display on the board at first, but there is a menu option to download the 3D models. After setting this up, and setting the solder mask colour to black, I was able to render the board properly. This looks very similar to the assembled board, with just a few parts missing.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-pcb-view-02-scaled.jpg&#34;
	width=&#34;2560&#34;
	height=&#34;1237&#34;
	srcset=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-pcb-view-02-scaled_hu_e2c45a40b41f5f39.jpg 480w, https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-pcb-view-02-scaled_hu_2e17145d17889523.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;206&#34;
		data-flex-basis=&#34;496px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;manufacturing&#34;&gt;Manufacturing
&lt;/h2&gt;&lt;p&gt;I only recently discovered that low-volume PCB manufacturing is accessible to hobbyists. Ordering the boards was really easy. I exported gerber and drill files according to their instructions, loaded them into a zip file, and uploaded them to a web portal.&lt;/p&gt;
&lt;p&gt;I am glad that an online gerber viewer was available, because it allowed me to spot an error which I had not noticed in KiCad, where I had two pins labelled PA1.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-manufacturing-01.png&#34;
	width=&#34;572&#34;
	height=&#34;218&#34;
	srcset=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-manufacturing-01_hu_3ffd02b9b7f058e1.png 480w, https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-manufacturing-01_hu_8e0fd9bb43da6b5e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;262&#34;
		data-flex-basis=&#34;629px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The default settings are reasonable, but I chose black solder mask, a lead-free surface finish, and chose the option to exclude the manufacturer&amp;rsquo;s order number from the board.&lt;/p&gt;
&lt;p&gt;The gerber viewer also has a tab which shows checks against their manufacturing rules.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-manufacturing-02.png&#34;
	width=&#34;2646&#34;
	height=&#34;1512&#34;
	srcset=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-manufacturing-02_hu_3947e371648db690.png 480w, https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-manufacturing-02_hu_66430c0b37b23ff.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;175&#34;
		data-flex-basis=&#34;420px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-manufacturing-03.png&#34;
	width=&#34;2582&#34;
	height=&#34;1474&#34;
	srcset=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-manufacturing-03_hu_407c4e11717f4e17.png 480w, https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-manufacturing-03_hu_218fd9720322c366.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;175&#34;
		data-flex-basis=&#34;420px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I placed the order, and eagerly checked each day as the boards progressed through the manufacturing steps. From placing the order to getting the boards on my desk, the whole process took 7 days.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-manufacturing-04.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-manufacturing-04_hu_5d99cf8afabbef42.jpg 480w, https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-manufacturing-04_hu_aada21cdfca611bf.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;assembly--test&#34;&gt;Assembly &amp;amp; test
&lt;/h2&gt;&lt;p&gt;Once all of the sockets arrived in the mail, I started assembling.&lt;/p&gt;
&lt;p&gt;The standard advice I&amp;rsquo;ve read for through-hole assembly is to solder low-profile components first. Instead, I added enough components to light up the power LED.&lt;/p&gt;
&lt;p&gt;I know that the power LED dims if anything is drawing too much current (eg. a short circuit). By getting this working first, I will know I&amp;rsquo;ve made a mistake (and can switch off the board quickly) if it doesn&amp;rsquo;t light up later.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-assemble-01.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-assemble-01_hu_35f8453ba9f85448.jpg 480w, https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-assemble-01_hu_c86c11808c8e5f42.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t think I&amp;rsquo;ve ever soldered more than a few pins or wires at a time, and this board had 323 pins to solder.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-assemble-02.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-assemble-02_hu_82fe13d789c4c492.jpg 480w, https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-assemble-02_hu_583ca7bce5380fd0.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;After a about 2 hours, I had a fully-populated board. It&amp;rsquo;s smaller and looks better than the breadboards, but it was time to move all the chips across to see if it actually worked.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-assemble-03.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-assemble-03_hu_2aab4c038a1495a3.jpg 480w, https://mike42.me/blog/2021-09-6502-computer-from-breadboard-to-pcb/2021-09-6502-computer-assemble-03_hu_199be604ca15ad08.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Much to my surprise, the computer booted up to EhBASIC on the first attempt.&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap-up
&lt;/h2&gt;&lt;p&gt;This has been quite a fun project. It has proven to me that open source tools are perfectly sufficient for this type of hardware development. I&amp;rsquo;m also very happy to have reached a point where can call this project &amp;ldquo;done&amp;rdquo;, since I have a permanent home-built computer.&lt;/p&gt;
&lt;p&gt;My plans for learning about low-level computing are not done yet, of course. I&amp;rsquo;ve kept everything at a low 1.8 MHz, so that I can continue to prototype hardware peripherals on a breadboard. I&amp;rsquo;ve also left a switch to select which half of ROM to boot from, so that I don&amp;rsquo;t brick my computer every time I make an error in an assembly language program.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve uploaded the full parts list, design files, and firmware to GitHub at &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/6502-computer&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/6502-computer&lt;/a&gt;.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Porting BASIC to my 6502 computer</title>
        <link>https://mike42.me/blog/2021-09-porting-basic-to-my-6502-computer</link>
        <pubDate>Thu, 09 Sep 2021 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2021-09-porting-basic-to-my-6502-computer</guid>
        <description>&lt;p&gt;I&amp;rsquo;ve recently been building my own &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/tag/6502&#34; &gt;6502-based computer&lt;/a&gt;. After a lot of work on the hardware side, I decided that it&amp;rsquo;s time to move past &amp;ldquo;Hello World&amp;rdquo; programs, and port a BASIC interpreter.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-09-porting-basic-to-my-6502-computer/2021-09-basic.png&#34;
	width=&#34;2040&#34;
	height=&#34;1282&#34;
	srcset=&#34;https://mike42.me/blog/2021-09-porting-basic-to-my-6502-computer/2021-09-basic_hu_e9cf59dac76c8149.png 480w, https://mike42.me/blog/2021-09-porting-basic-to-my-6502-computer/2021-09-basic_hu_1d94a13ebfc1f143.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;159&#34;
		data-flex-basis=&#34;381px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;background&#34;&gt;Background
&lt;/h2&gt;&lt;p&gt;This computer is architecturally similar to a 1980&amp;rsquo;s home computer, where BASIC was a widely-used interpreted language. Porting an existing interpreter will be a fast way to get a command-prompt, and it will also add the ability to load arbitrary software, by typing out a program.&lt;/p&gt;
&lt;p&gt;I heard about an interpreter called EhBASIC (&amp;ldquo;Enhanced BASIC&amp;rdquo;) from on &lt;a class=&#34;link&#34; href=&#34;https://www.youtube.com/watch?v=k1iv2ANb2Ko&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this YouTube video by Chris Bird&lt;/a&gt;. It&amp;rsquo;s source-available (free for non-commercial use only), and seems to be well-regarded by 6502 enthusiasts.&lt;/p&gt;
&lt;p&gt;EhBASIC was written by the late Lee Davidson. I based my port on the version v2.22, hosted on &lt;a class=&#34;link&#34; href=&#34;https://github.com/Klaus2m5/6502_EhBASIC_V2.22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Klaus Dormann&amp;rsquo;s GitHub&lt;/a&gt;. I used Hans Otten&amp;rsquo;s &lt;a class=&#34;link&#34; href=&#34;http://retro.hansotten.nl/6502-sbc/lee-davison-web-site/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mirror of Lee&amp;rsquo;s website&lt;/a&gt; as a reference, plus the &lt;a class=&#34;link&#34; href=&#34;http://forum.6502.org/viewforum.php?f=5&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;EhBASIC section&lt;/a&gt; of the 6502.org forum.&lt;/p&gt;
&lt;h2 id=&#34;porting-process&#34;&gt;Porting process
&lt;/h2&gt;&lt;p&gt;EhBASIC was a breeze to port.&lt;/p&gt;
&lt;p&gt;I started with the &amp;lsquo;patched&amp;rsquo; code from &lt;a class=&#34;link&#34; href=&#34;https://github.com/Klaus2m5/6502_EhBASIC_V2.22/tree/master/patched&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Klaus2m5/6502_EhBASIC_V2.22&lt;/a&gt;, which I placed in a local git repository, so that I could track the changes.&lt;/p&gt;
&lt;p&gt;I first changed some of the syntax so that the code would assemble with &lt;code&gt;ca65&lt;/code&gt;, since that is the assembler I&amp;rsquo;m using for everything else. There are &lt;a class=&#34;link&#34; href=&#34;https://github.com/jefftranter/6502/tree/master/asm/ehbasic&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;other ca65 ports around&lt;/a&gt;, though they do not include the same patches.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;--feature labels_without_colons&lt;/code&gt; setting in &lt;code&gt;ca65&lt;/code&gt; was useful here, since the original source does not include colons after label names. The output was 10.5KiB of machine code, which will fit in the 16KiB of ROM space which I have available in my home-built computer.&lt;/p&gt;
&lt;p&gt;I also confirmed that the code did not depend on using undocumented 6502 CPU opcodes, which would have been incompatible with my newer-generation 65C02 CPU.&lt;/p&gt;
&lt;p&gt;Next, I dropped in the correct routines to read and write characters. I already had something &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer&#34; &gt;similar from an earlier blog post&lt;/a&gt;. I needed to make some small changes to use the carry bit (&lt;code&gt;SEC&lt;/code&gt; / &lt;code&gt;CLC&lt;/code&gt; opcodes) to indicate whether a character had been received, and to set up the 6551 ACIA on startup. I programmed the code to an EEPROM, and it worked the first time.&lt;/p&gt;
&lt;p&gt;All of my changes against the original code, including the Makefile and &lt;code&gt;ca65&lt;/code&gt; config file are &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/6502-computer/commit/f87902d4b3cca313ebdcd039b687da0f20d996e6&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;in this commit&lt;/a&gt;. The memory addresses line up with the decoding scheme &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer&#34; &gt;described here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap-up
&lt;/h2&gt;&lt;p&gt;BASIC is an interesting language, if only for historical reasons. Classic BASIC feels very clunky by modern standards, but the user experience is not that different to the modern Python REPL. Or at least, it is more similar than you might expect given how far computers have advanced.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m running EhBASIC on an 8-bit CPU, where the main alternative is plain 6502 assembly language. BASIC has allowed me to hit the ground running, and gives me access to floating point maths and user-loadable programs, on a computer that does not have an operating system or removable storage.&lt;/p&gt;
&lt;p&gt;My home-built computer has &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer&#34; &gt;a switch&lt;/a&gt; for selecting between two ROM&amp;rsquo;s. My plan is to write my own code in assembly language, but keep this port of EhBASIC in the secondary ROM, so that the computer can always boot to something that works.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Upgrades and improvements to my 6502 computer</title>
        <link>https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer</link>
        <pubDate>Thu, 26 Aug 2021 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer</guid>
        <description>&lt;p&gt;For the past few weeks, I&amp;rsquo;ve been building a &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/tag/6502&#34; &gt;6502-based&lt;/a&gt; retro computer, based originally on a &lt;a class=&#34;link&#34; href=&#34;https://eater.net/6502&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;tutorial and design by Ben Eater&lt;/a&gt;. My first major change was to &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer&#34; &gt;add a serial port&lt;/a&gt;, so that I can write programs which accept text as input.&lt;/p&gt;
&lt;p&gt;This blog post is a list of things which I&amp;rsquo;ve changed since, to try to make a computer which is a bit more suited to my intended use. My aim at the moment is to lock in a simple base system, so that I can use it as permanent platform for 6502 assembly and hardware experiments.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-modified.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-modified_hu_49d10a2cc7d55e36.jpg 480w, https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-modified_hu_539e45cc5d956990.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;re-visiting-address-decoding&#34;&gt;Re-visiting address decoding
&lt;/h2&gt;&lt;p&gt;The computer has a 32 KiB RAM chip, and a 32 KiB ROM chip. Due to the way that the &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Glue_logic&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;glue logic&lt;/a&gt; was set up, only 16 KiB of the RAM can be used, but the full ROM space is available.&lt;/p&gt;
&lt;p&gt;I wanted to flip this around, since I&amp;rsquo;m planning to run most programs from RAM, with only a loader or interpreter in the ROM. The idea would be to add a switch to select between the upper and lower half of ROM, map the full RAM in, and leave a large space available for I/O and other experiments.&lt;/p&gt;
&lt;p&gt;I planned out a coarse, 2-chip address decoder to achieve this.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-addr-decode-new.png&#34;
	width=&#34;1281&#34;
	height=&#34;548&#34;
	srcset=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-addr-decode-new_hu_20d696890f147dc9.png 480w, https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-addr-decode-new_hu_80f9abcc81cf8017.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;233&#34;
		data-flex-basis=&#34;561px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The resulting memory map is:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Address&lt;/th&gt;
          &lt;th&gt;Maps to&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;C000-FFFF&lt;/td&gt;
          &lt;td&gt;ROM - 16 KiB&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;A000-BFFF&lt;/td&gt;
          &lt;td&gt;Not decoded - 8 KiB&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;8000-9FFF&lt;/td&gt;
          &lt;td&gt;I/O - 8 KiB&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;0000-7FFF&lt;/td&gt;
          &lt;td&gt;RAM&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This is partly based on the info in &lt;a class=&#34;link&#34; href=&#34;https://wilsonminesco.com/6502primer/addr_decoding.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Garth Wilson&amp;rsquo;s address decoding primer&lt;/a&gt;, and also &lt;a class=&#34;link&#34; href=&#34;https://sbc.rictor.org/info2.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Daryl Richtor&amp;rsquo;s SBC-2&lt;/a&gt; computer.&lt;/p&gt;
&lt;p&gt;I re-wired every chip select, modified my test program to use the new memory map, and also added a switch to select between the two halves of the ROM.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-addr-decoder-new-02.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-addr-decoder-new-02_hu_de7ef3fda5878dd5.jpg 480w, https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-addr-decoder-new-02_hu_85bfead8a16fd3a7.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;implementing-power-on-reset&#34;&gt;Implementing power-on reset
&lt;/h2&gt;&lt;p&gt;In Ben Eater&amp;rsquo;s 6502 computer, the reset line is connected to +5v through a resistor, and grounded when a momentary switch is pressed. At power-on, I needed to press the reset button before the computer would do anything useful.&lt;/p&gt;
&lt;p&gt;I removed the pull-up resistor from the reset line, and added a DS1813-5+ supervisory IC instead. This holds the reset line low for 150ms at power-on, or when reset is pressed. This suggestion was from the &lt;a class=&#34;link&#34; href=&#34;http://forum.6502.org/viewtopic.php?f=12&amp;amp;t=4365&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;6502.org forums&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-reset-ic.png&#34;
	width=&#34;190&#34;
	height=&#34;144&#34;
	srcset=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-reset-ic_hu_5f5da0581d64457b.png 480w, https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-reset-ic_hu_757acb02cccb7c20.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;131&#34;
		data-flex-basis=&#34;316px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;There was no KiCad symbol for the DS1813-5 in the default library, so I needed to create one.&lt;/p&gt;
&lt;h2 id=&#34;interrupt-lines&#34;&gt;Interrupt lines
&lt;/h2&gt;&lt;p&gt;I found that I had made an error when connecting the interrupt lines.&lt;/p&gt;
&lt;p&gt;The 6502 has two interrupt inputs: IRQ and NMI. On my 6502 computer, the interrupt output of the 65C22S is connected to the IRQ input of the CPU, while the interrupt output of the 65C51S is connected to the NMI input of the CPU.&lt;/p&gt;
&lt;p&gt;The 65C51N uses an open-drain IRQ output, so this configuration left the CPU&amp;rsquo;s NMI input floating most of the time, which caused many spurious interrupts. This was easily fixed by connecting the NMI line to +5v through a 3.3k resistor.&lt;/p&gt;
&lt;p&gt;I also implemented &lt;a class=&#34;link&#34; href=&#34;http://wilsonminesco.com/6502primer/MysteryPins.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;some tips&lt;/a&gt; from Garth Wilson&amp;rsquo;s 6502 primer, and connected &lt;code&gt;RDY&lt;/code&gt; and &lt;code&gt;BE&lt;/code&gt; to +5v through 3.3k resistors, where they had previously been connected to +5v directly.&lt;/p&gt;
&lt;h2 id=&#34;power&#34;&gt;Power
&lt;/h2&gt;&lt;p&gt;Up until this point, I had been powering my computer with a breadboard power supply. I&amp;rsquo;m hoping to build something permanent, so I designed a circuit to power it through a DC barrel jack.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-power-supply-01.png&#34;
	width=&#34;749&#34;
	height=&#34;356&#34;
	srcset=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-power-supply-01_hu_f964c076c0fffd29.png 480w, https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-power-supply-01_hu_22687410c7a5eecc.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;210&#34;
		data-flex-basis=&#34;504px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This takes a DC voltage, and steps it down to 5v through a voltage regulator. The other components are a power switch, plus a diode so that I can avoid damaging anything if I connect a plug with the wrong polarity.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-power-supply-02.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-power-supply-02_hu_e4733182b674d768.jpg 480w, https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-power-supply-02_hu_ab0da3150ff45a0e.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This computer does not draw much current, so it&amp;rsquo;s not necessary to add a heat-sink on the voltage regulator.&lt;/p&gt;
&lt;h2 id=&#34;getting-my-wires-crossed&#34;&gt;Getting my wires crossed
&lt;/h2&gt;&lt;p&gt;My next change was to remove the LCD screen. This had been useful for debugging, but I would prefer to free up breadboard space and I/O connections for other parts of this project.&lt;/p&gt;
&lt;p&gt;I did this in four steps, testing after each one. First I moved the LCD off to its own breadboard, then updated the computer&amp;rsquo;s test program to stop using the LCD, ran the computer without the LCD connected, and finally re-located the UART chip into the newly-vacant space.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-screen-move-01.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-screen-move-01_hu_9403b9c6f93c95b0.jpg 480w, https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-screen-move-01_hu_69409de69e6b918d.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;After the last step, the computer started producing the wrong text (eg. &amp;ldquo;H&amp;rdquo; became &amp;ldquo;D&amp;rdquo;). I had mixed up two bits in the data bus, and by some luck the UART setup code was not affected. The orange and red wires on the left of this photo are the ones which were swapped.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-screen-move-02.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-screen-move-02_hu_58dcbb2c509f3c1a.jpg 480w, https://mike42.me/blog/2021-08-upgrades-and-improvements-to-my-6502-computer/2021-08-screen-move-02_hu_e1532e7bac61d22a.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I was able narrow down the source of the problem quickly, since I was breaking everything down into small steps, which were easy to individually verify.&lt;/p&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next steps
&lt;/h2&gt;&lt;p&gt;For all this effort, not much has changed. I still just have an 8-bit computer which says &amp;ldquo;Hello&amp;rdquo; when it starts. The next part of this project will involve porting across some non-trivial software.&lt;/p&gt;
&lt;p&gt;On the hardware side, I&amp;rsquo;ve made a lot of progress learning how to use KiCad. As long as everything works, my plan is to migrate this design from breadboard to a PCB in the near future.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>A first look at programmable logic</title>
        <link>https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic</link>
        <pubDate>Thu, 12 Aug 2021 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic</guid>
        <description>&lt;p&gt;I&amp;rsquo;ve recently been learning a bit about how computers work on a low-level by &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/tag/6502&#34; &gt;building a 6502-based retro computer from scratch&lt;/a&gt;. I&amp;rsquo;ve noticed that plenty of retro computer designs use simple programmable logic devices, including GAL&amp;rsquo;s, PAL&amp;rsquo;s and PLA&amp;rsquo;s.&lt;/p&gt;
&lt;p&gt;I decided to take a closer look at these, since they may be a useful part of my toolkit. The particular part which grabbed my attention was the &lt;a class=&#34;link&#34; href=&#34;https://www.microchip.com/wwwproducts/en/ATF22V10C&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;ATF22V10&lt;/a&gt; programmable logic device (PLD).&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-01.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-01_hu_a8659b40786e3cee.jpg 480w, https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-01_hu_b692f4f7d14abd13.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This ticks a few important boxes for my current projects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Available in DIP packaging, so it is suitable for use on a breadboard.&lt;/li&gt;
&lt;li&gt;Operates at 5 volts.&lt;/li&gt;
&lt;li&gt;Currently in production.&lt;/li&gt;
&lt;li&gt;Has a relatively high pin count (slightly more than the ATF16V8).&lt;/li&gt;
&lt;li&gt;Can be programmed using a TL866II+ programmer, which I already use for EEPROM programming.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These devices have been around for many decades, and I found mixed information online about the software and hardware requirements for programming these chips. A lot more has been written about the (discontinued) Lattice 22V10, which has similar capabilities, but a different programming process.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-a-programming-environment&#34;&gt;Setting up a programming environment
&lt;/h2&gt;&lt;p&gt;The logic functions for programming the ATF22V10 are specified using a human-readable hardware description language, which needs to be compiled into a device-specific &amp;ldquo;fuse map&amp;rdquo; for programming the device.&lt;/p&gt;
&lt;p&gt;The only real choice for the ATF22V10 seems to be an obscure language called CUPL, which can be processed by Atmel/Microchip&amp;rsquo;s proprietary compiler, &lt;a class=&#34;link&#34; href=&#34;https://www.microchip.com/en-us/development-tool/WinCUPL&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;WinCUPL&lt;/a&gt;. This is distributed as a freeware Windows binary, downloadable from &lt;a class=&#34;link&#34; href=&#34;https://www.microchip.com/en-us/products/fpgas-and-plds/spld-cplds/pld-design-resources&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this page&lt;/a&gt; on the Microchip website.&lt;/p&gt;
&lt;p&gt;I do all of my other software development on Linux, so I installed WinCUPL in a WINE environment. On Ubuntu 20.04, WINE is installed with the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install wine
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For later parts of the process, I found that I also needed &lt;code&gt;winetricks&lt;/code&gt; and &lt;code&gt;cabextract&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install cabextract
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wget https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chmod +x winetricks
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The install was simple:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wine awincupl.exe
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I was then launching the program with the following command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ wine  ~/.wine/drive_c/Wincupl/WinCupl/Wincupl.exe
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On first start-up, it prompted for registration info. This is a carry-over from before this tool was freeware, and the download page lists the correct key as &lt;code&gt;60008009&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-02.png&#34;
	width=&#34;503&#34;
	height=&#34;223&#34;
	srcset=&#34;https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-02_hu_8b5f077a3cca33f4.png 480w, https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-02_hu_94c7db2c37cc2a8.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;225&#34;
		data-flex-basis=&#34;541px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I got persistent errors about missing DLL modules.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-03.png&#34;
	width=&#34;639&#34;
	height=&#34;489&#34;
	srcset=&#34;https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-03_hu_9ab6097bfd3f9e40.png 480w, https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-03_hu_f4c7b072a86abd59.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;130&#34;
		data-flex-basis=&#34;313px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I initially thought that this was a library registration or 32/64-bit compatibility issue, though I eventually found that I needed to install &lt;code&gt;mfc40&lt;/code&gt; via &lt;code&gt;winetrics&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ./winetricks mfc40
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After this installer ran, I was able to launch WinCUPL. The editor was using a a proportional font, though the dialog indicated that it was attempting to use Courier New, which is monospace.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-04.png&#34;
	width=&#34;620&#34;
	height=&#34;404&#34;
	srcset=&#34;https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-04_hu_4e3fcadb0f50a30e.png 480w, https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-04_hu_3f8c348553670784.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;153&#34;
		data-flex-basis=&#34;368px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This is fixed by installing the Microsoft fonts via the &lt;code&gt;ttf-mscorefonts-installer&lt;/code&gt; package.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get --reinstall install ttf-mscorefonts-installer
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At this point I had a working editor. If it was not clear yet that this is ancient technology, this screen capture shows the I/O decoding example which is bundled with WinCUPL, which was apparently written in 1984.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-05.png&#34;
	width=&#34;944&#34;
	height=&#34;667&#34;
	srcset=&#34;https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-05_hu_25b7f65552713eba.png 480w, https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-05_hu_87a2640944f1f549.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;141&#34;
		data-flex-basis=&#34;339px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;writing-a-test-program&#34;&gt;Writing a test program
&lt;/h2&gt;&lt;p&gt;WinCUPL ships with a folder of example programs, and some documentation which includes a reference manual and tutorial. Most introductory information online seems to be from old electrical or computer engineering courses.&lt;/p&gt;
&lt;p&gt;I read through:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://class.ece.uw.edu/475/peckol/doc/cupl.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;This CUPL tutorial from 1998&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://ecee.colorado.edu/~mcclurel/WinCUPL_Intro_handouts2.pdf&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;These slides from 2008&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The closest thing to a &amp;ldquo;Hello World&amp;rdquo; program for one of these chips is the &lt;code&gt;GATES.PLD&lt;/code&gt; example, which shows how to apply some basic logic operations. It was written for the &lt;code&gt;ATF16V8&lt;/code&gt;, so I looked up my own device to find its mnemonic, &lt;code&gt;g22v10&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-08.png&#34;
	width=&#34;528&#34;
	height=&#34;516&#34;
	srcset=&#34;https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-08_hu_ef2a939daf8c0738.png 480w, https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-08_hu_bf093a84d1f8c245.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;102&#34;
		data-flex-basis=&#34;245px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;After swapping around the pins, I ended up with this program for testing the ATF22V10:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Name     MyTest;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PartNo   00;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Date     6/07/2021;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Revision 01;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Designer Mike;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Company  None;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Assembly None;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Location None;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Device   g22v10;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Pin 1 = a;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Pin 2 = b;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Pin 14 = inva;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Pin 15 = invb;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Pin 16 = and;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Pin 17 = nand;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Pin 18 = or;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Pin 19 = nor;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Pin 20 = xor;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Pin 21 = xnor;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;inva = !a;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;invb = !b;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;and = a &amp;amp; b;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nand = !(a &amp;amp; b);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;or = a # b;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nor = !(a # b);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;xor = a $ b;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;xnor = !(a $ b);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To get a JED file from this, I navigated to compile options, and disabled the &amp;ldquo;Simulate&amp;rdquo; and &amp;ldquo;Absolute&amp;rdquo; options. This skips the simulation step, which otherwise blocks compilation.&lt;/p&gt;
&lt;p&gt;I did not find the simulator very intuitive, but I did return to it later after watching &lt;a class=&#34;link&#34; href=&#34;https://www.youtube.com/watch?v=qxJI961dyNE&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this recent tutorial&lt;/a&gt;. The devices can only be reprogrammed 100 times, so for anything complex, I&amp;rsquo;ll definitely be checking outputs in the simulator rather than relying on trial-and-error.&lt;/p&gt;
&lt;h2 id=&#34;programming-the-chip&#34;&gt;Programming the chip
&lt;/h2&gt;&lt;p&gt;I use TL866II+ programmer with the &lt;a class=&#34;link&#34; href=&#34;https://gitlab.com/DavidGriffith/minipro&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;minipro&lt;/a&gt; open source programming software for other chips, and I found mixed information online about whether this would work for the ATF22V10.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-06.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-06_hu_a11776bd7777ff38.jpg 480w, https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-06_hu_351cf85a084b48b3.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;In my case, it worked, but only after a few attempts. My first mistake was to &lt;strong&gt;read&lt;/strong&gt; the chip instead of &lt;strong&gt;writing it&lt;/strong&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ minipro -p ATF22V10CQZ -r MyTest.jed
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Found TL866II+ 04.2.86 (0x256)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Warning: Firmware is out of date.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Expected  04.2.123 (0x27b)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Found     04.2.86 (0x256)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Reading device...  0.54Sec  OK
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When I plugged this into my test circuit (shown later), the blank chip warmed up, and produced erratic output.&lt;/p&gt;
&lt;p&gt;After re-generating the JED file, I programmed the chip again, but got some warnings and verification errors. The chip still produced heat and erratic output in my test circuit.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ minipro -p ATF22V10CQZ -w MyTest.jed
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Found TL866II+ 04.2.86 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;0x256&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Warning: Firmware is out of date.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Expected  04.2.123 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;0x27b&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Found     04.2.86 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;0x256&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;VPP&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;12V
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Warning! JED file doesn&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;t match the selected device!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Declared fuse checksum: 0x7005 Calculated: 0x7005 ... OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Declared file checksum: 0x6DDD Calculated: 0x6DDD ... OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;JED file parsed OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Use -P to skip write protect
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Erasing... 0.82Sec OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Writing jedec file...  4.97Sec  OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Reading device...  0.54Sec  OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Writing lock bit... 0.26Sec OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Verification failed at address 0x0006: &lt;span class=&#34;nv&#34;&gt;File&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0x00, &lt;span class=&#34;nv&#34;&gt;Device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0x01
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Reading back the device produced a completely different JED file (different length, different contents).&lt;/p&gt;
&lt;h3 id=&#34;detour-firmware-update&#34;&gt;Detour: Firmware update
&lt;/h3&gt;&lt;p&gt;I started digging into the warnings, and decided to attempt a firmware update. The best instructions I could find for this were from &lt;a class=&#34;link&#34; href=&#34;https://gitlab.com/DavidGriffith/minipro/-/issues/185&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this GitLab issue&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The short version is that once you have a firmware file from the hardware vendor, they can be applied by &lt;code&gt;minipro&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ minipro -F updateII.dat
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Found TL866II+ 04.2.86 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;0x256&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Warning: Firmware is out of date.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Expected  04.2.123 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;0x27b&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Found     04.2.86 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;0x256&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;updateII.dat contains firmware version 4.2.126 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;newer&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Do you want to &lt;span class=&#34;k&#34;&gt;continue&lt;/span&gt; with firmware update? y/n:y
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Switching to bootloader... failed!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I got this error, probably because the device was restarted. On my setup, I am passing the USB device through to a VM, and needed to press a button to redirect it again.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;minipro&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;F&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;updateII&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dat&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Found&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TL866II&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bootloader&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;updateII&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dat&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;contains&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;firmware&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;version&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;4.2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;126&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;newer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Do&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;you&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;want&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;continue&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;firmware&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;update&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Erasing&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;OK&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Reflashing&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Resetting&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;OK&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Reflash&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;OK&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;programming-the-chip-again&#34;&gt;Programming the chip again
&lt;/h3&gt;&lt;p&gt;With the updated firmware, I made a third attempt to write the chip, using the same JED file as before.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ minipro -p ATF22V10CQZ -w MyTest.jed
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Found TL866II+ 04.2.126 (0x27e)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Warning: Firmware is newer than expected.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Expected  04.2.123 (0x27b)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Found     04.2.126 (0x27e)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;VPP=12V
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Warning! JED file doesn&amp;#39;t match the selected device!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Declared fuse checksum: 0x7005 Calculated: 0x7005 ... OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Declared file checksum: 0x6DDD Calculated: 0x6DDD ... OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;JED file parsed OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Use -P to skip write protect
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Erasing... 0.33Sec OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Writing jedec file...  5.04Sec  OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Reading device...  0.41Sec  OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Writing lock bit... 0.35Sec OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Verification failed at address 0x16C6: File=0x01, Device=0x00
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Reading the device returned a JED file with all 0&amp;rsquo;s, and there are still some warnings, but the circuit appeared to work correctly.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-07.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-07_hu_a7c85e6ab9e316ed.jpg 480w, https://mike42.me/blog/2021-08-a-first-look-at-programmable-logic/2021-08-programmable-logic-07_hu_3e24d0e2fb2665c2.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;alternatives&#34;&gt;Alternatives
&lt;/h2&gt;&lt;p&gt;The firmware update seemed to fix any problems for me, but I have read plenty of accounts of &lt;a class=&#34;link&#34; href=&#34;http://forum.6502.org/viewtopic.php?f=10&amp;amp;t=6065&amp;amp;start=30&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;tricky issues&lt;/a&gt; when attempting to program the ATF22V10 with the TL866II+ programmer.&lt;/p&gt;
&lt;p&gt;An alternative programmer might be the Wellon VP-290 (&lt;a class=&#34;link&#34; href=&#34;http://forum.6502.org/viewtopic.php?f=10&amp;amp;t=3518&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mentioned here&lt;/a&gt;). On the software side, using the ATF22V10 really seems to require WinCUPL, though it does have a command-line.&lt;/p&gt;
&lt;p&gt;There is plenty of software designed for the discontinued Lattice 22V10 GAL, though my best guess is that these are not compatible with the Atmel chips I&amp;rsquo;m using here. These include &lt;a class=&#34;link&#34; href=&#34;https://github.com/daveho/GALasm&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;GALasm&lt;/a&gt;, which has a license which prohibits commercial use (enough for me to steer clear), plus an open source re-implementation called &lt;a class=&#34;link&#34; href=&#34;https://github.com/simon-frankau/galette&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;galette&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap-up
&lt;/h2&gt;&lt;p&gt;It&amp;rsquo;s been interesting to take a look at the lowest-possible level of the software stack, even just to produce a &amp;ldquo;Hello World&amp;rdquo; program.&lt;/p&gt;
&lt;p&gt;I am not using PLD&amp;rsquo;s in my current project, but it&amp;rsquo;s good to know that I could program one if I needed to. The main use for me would be as an alternative to discrete logic chips, so that I can keep parts count, layout space, and propagation delays under control. For prototyping, it will also be helpful to be able to replicate old circuits which use similar components, or to simulate logic chips which aren&amp;rsquo;t in my inventory.&lt;/p&gt;
&lt;p&gt;One thing that I learned is that a fuse is not the same as a gate. The device I used has thousands of fuses (programmable connections) which are capable of configuring the inputs to a few hundred gates. If the temperature of my first two programming attempts is anything to go by, it seems to be perfectly possible to configure the fuses to produce a short circuit.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Adding a serial port to my 6502 computer</title>
        <link>https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer</link>
        <pubDate>Thu, 22 Jul 2021 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer</guid>
        <description>&lt;p&gt;In &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-07-building-a-6502-computer&#34; &gt;my last blog post&lt;/a&gt;, I wrote about the 8-bit computer which I&amp;rsquo;ve been building, using an existing design by Ben Eater. The I/O capabilities of the original design are rather limited, so one of the first enhancements I&amp;rsquo;m making is to add a serial port.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-15-computer-serial-port-01.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-15-computer-serial-port-01_hu_125b425e651d13b6.jpg 480w, https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-15-computer-serial-port-01_hu_a68e205c0baaf492.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;hardware&#34;&gt;Hardware
&lt;/h2&gt;&lt;p&gt;The main chip I am adding is the WDC 65C51N ACIA, which is a modern version of the MOS 6551. Versions of this chip have been on the market for around 40 years, and lots of classic computer designs use some version of it for serial output. I bought this one new, and the date code indicates that it was manufactured 11 years ago, so it&amp;rsquo;s a fair guess that they are not selling as fast as they used to.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-15-computer-serial-port-02.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-15-computer-serial-port-02_hu_5eb6d1ea48ca5e27.jpg 480w, https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-15-computer-serial-port-02_hu_3a0e3725d96aa87c.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I also needed a 1.8432 MHz oscillator, which I used to clock both the computer and the UART.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-15-computer-serial-port-03.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-15-computer-serial-port-03_hu_e4bb4214635c6acb.jpg 480w, https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-15-computer-serial-port-03_hu_8b554e5e0cc285e4.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Lastly, I used a USB/UART module to interface with a modern computer. This module hosts a FT232RL chip, and the pins on this one are &lt;code&gt;DTR&lt;/code&gt;, &lt;code&gt;RX&lt;/code&gt;, &lt;code&gt;TX&lt;/code&gt;, &lt;code&gt;VCC&lt;/code&gt;, &lt;code&gt;CTS&lt;/code&gt; and &lt;code&gt;GND&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-15-computer-serial-port-04.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-15-computer-serial-port-04_hu_3b5bfecb718ab462.jpg 480w, https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-15-computer-serial-port-04_hu_8b70920941eb2496.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;address-decoding&#34;&gt;Address decoding
&lt;/h2&gt;&lt;p&gt;The 65C02 CPU in my computer uses memory-mapped I/O, so I needed to fit this new I/O chip into the memory map before I could start using it.&lt;/p&gt;
&lt;p&gt;The original design uses a single-chip solution for address decoding, where the select lines for the ROM, RAM, and a 65C22 VIA chip are connected via 3 NAND gates.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-computer-serial-port-07.png&#34;
	width=&#34;525&#34;
	height=&#34;331&#34;
	srcset=&#34;https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-computer-serial-port-07_hu_8c8a1e06673a95b.png 480w, https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-computer-serial-port-07_hu_1be2b8942c523f6d.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;158&#34;
		data-flex-basis=&#34;380px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This leaves an unused space between address 4000 and address 5FFF.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Address&lt;/th&gt;
          &lt;th&gt;Maps to&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;8000-FFFF&lt;/td&gt;
          &lt;td&gt;ROM&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;6000-7FFF&lt;/td&gt;
          &lt;td&gt;I/O - 65C22 VIA&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;4000-5FFF&lt;/td&gt;
          &lt;td&gt;Not decoded&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;0000-3FFF&lt;/td&gt;
          &lt;td&gt;RAM&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The 65C51 ACIA has two chip select inputs: one active-high and one active-low, much the same as the 65C22 VIA. All I needed to do was invert A13, and there was an unused NAND gate in the existing design which I could use for it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-computer-serial-port-06.png&#34;
	width=&#34;525&#34;
	height=&#34;381&#34;
	srcset=&#34;https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-computer-serial-port-06_hu_cd4922b22a826e48.png 480w, https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-computer-serial-port-06_hu_56b5a567131ee8ef.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;137&#34;
		data-flex-basis=&#34;330px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This places the 65C51 in the unused address space. It&amp;rsquo;s not exactly efficient to assign 8KB of address space to a device which needs 4 bytes, but it does work.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Address&lt;/th&gt;
          &lt;th&gt;Maps to&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;8000-FFFF&lt;/td&gt;
          &lt;td&gt;ROM&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;6000-7FFF&lt;/td&gt;
          &lt;td&gt;I/O - 65C22 VIA.&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;4000-5FFF&lt;/td&gt;
          &lt;td&gt;UART - 65C51 ACIA&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;0000-3FFF&lt;/td&gt;
          &lt;td&gt;RAM&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;While editing this blog post, I also re-read Garth Wilson&amp;rsquo;s &lt;a class=&#34;link&#34; href=&#34;http://wilsonminesco.com/6502primer/addr_decoding.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;address decoding guide&lt;/a&gt; for the 6502, which shows some alternative schemes for achieving this.&lt;/p&gt;
&lt;h2 id=&#34;wiring&#34;&gt;Wiring
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;m using the following wiring between the 65C51 and the USB/UART module.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-computer-serial-port-08.png&#34;
	width=&#34;525&#34;
	height=&#34;578&#34;
	srcset=&#34;https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-computer-serial-port-08_hu_caf7b8bcdee5eb0d.png 480w, https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-computer-serial-port-08_hu_37deda691f1c1335.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;90&#34;
		data-flex-basis=&#34;217px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Note: The the two clock inputs are connected to the 1.8432 MHz oscillator, which is not shown correctly here.&lt;/p&gt;
&lt;h2 id=&#34;software&#34;&gt;Software
&lt;/h2&gt;&lt;p&gt;This particular revision of the 6551 has some &lt;a class=&#34;link&#34; href=&#34;http://forum.6502.org/viewtopic.php?f=4&amp;amp;t=2543&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;hardware bugs&lt;/a&gt;, though they are well-documented and can be worked around in software. Most of the &lt;a class=&#34;link&#34; href=&#34;http://retro.hansotten.nl/6502-sbc/lee-davison-web-site/acia-6551/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;excellent example code&lt;/a&gt; online is aimed at older (less buggy) revisions.&lt;/p&gt;
&lt;p&gt;After four attempts, I was able to write an assembly-language program which could produce some output. The information on &lt;a class=&#34;link&#34; href=&#34;http://forum.6502.org/viewtopic.php?f=4&amp;amp;t=5495&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this 6502.org thread&lt;/a&gt;, and &lt;a class=&#34;link&#34; href=&#34;http://forum.6502.org/viewtopic.php?f=4&amp;amp;t=2543&amp;amp;start=30#p29795&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this 6502.org comment&lt;/a&gt; were the most accurate for my hardware setup.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m using this code to set up the ACIA for 8-N-1 communication at 19,200 bytes per second, with no interrupts.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;ACIA_RX&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$4000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;ACIA_TX&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$4000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;ACIA_STATUS&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$4001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;ACIA_COMMAND&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$4002&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;ACIA_CONTROL&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;$4003&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;reset:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;c1&#34;&gt;; ... other stuff
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;c1&#34;&gt;; ACIA setup
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$00
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ACIA_STATUS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$0b
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ACIA_COMMAND&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$1f
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ACIA_CONTROL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;c1&#34;&gt;; ... other stuff
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To send, I needed to add a delay between bytes, since the hardware bug prevents the transmit bit in the status register from operating correctly. I found some code with nested loops, but it only worked after increasing the delay far beyond what should have been necessary. An alternative work-around is to generate a timed interrupt from the 65C22 VIA, which I&amp;rsquo;m hoping to try later.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; print A register to ACIA
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Based on http://forum.6502.org/viewtopic.php?f=4&amp;amp;t=2543&amp;amp;start=30#p29795
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;print_char_acia:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;pha&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ACIA_STATUS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;pla&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ACIA_TX&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;jsr&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;delay_6551&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;rts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;delay_6551:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nf&#34;&gt;phy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nf&#34;&gt;phx&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;delay_loop:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;ldy&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#6 ; inflated from numbers in original code.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;minidly:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;ldx&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$68
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;delay_1:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;dex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;bne&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;delay_1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;dey&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;bne&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;minidly&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;plx&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;ply&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;delay_done:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;rts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I am using this routine to receive characters. It will block until the next character is received, and I will most likely need to replace this with something interrupt-driven once I start to add more complex programs.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; hang until we have a character, return it via A register.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;recv_char_acia:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ACIA_STATUS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#$08
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;beq&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;recv_char_acia&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;lda&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ACIA_RX&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;rts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I ended up with a program which prints &amp;ldquo;Hello&amp;rdquo; to both the LCD and serial port when the computer resets, then accepts text input. Any characters received over serial are then printed back to the terminal, and also to the LCD.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-15-computer-serial-port-05-1.png&#34;
	width=&#34;1572&#34;
	height=&#34;1066&#34;
	srcset=&#34;https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-15-computer-serial-port-05-1_hu_506529f58ab74a1a.png 480w, https://mike42.me/blog/2021-07-adding-a-serial-port-to-my-6502-computer/2021-07-15-computer-serial-port-05-1_hu_4081ee42d603bb0a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;147&#34;
		data-flex-basis=&#34;353px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;mistakes-were-made&#34;&gt;Mistakes were made
&lt;/h2&gt;&lt;p&gt;Since this is a learning project, I&amp;rsquo;m keeping a log of mistakes that I&amp;rsquo;m making along the way. Today&amp;rsquo;s lesson is to check everything, because it&amp;rsquo;s very difficult to debug multiple problems at once. When I ran my first test program, there were four faults.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I interfaced the USB/UART module to the 65C51 by matching up pin names, which does not work - RX on one side of the serial connection should go to TX on the other.&lt;/li&gt;
&lt;li&gt;I incorrectly calculated the memory map, so the test program was writing to address 8000 while the 65C51 was mapped to address 4000.&lt;/li&gt;
&lt;li&gt;I based my code on examples which do not work on this chip revision, because of the hardware bug noted above.&lt;/li&gt;
&lt;li&gt;I also miscalculated the baud rate, so even if I didn&amp;rsquo;t have the other faults, my settings for &lt;code&gt;minicom&lt;/code&gt; would not have worked.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap-up
&lt;/h2&gt;&lt;p&gt;It&amp;rsquo;s very straightforward to modify Ben Eater&amp;rsquo;s 6502 computer design by adding a 65C51 ACIA. This upgrade will allow me to write (or port) software which uses text I/O. I&amp;rsquo;m planning a few more changes to this design before I port anything too serious though.&lt;/p&gt;
&lt;p&gt;This is also the first time I&amp;rsquo;ve included (pieces of) schematics in a blog post. I&amp;rsquo;m drawing these with KiCad, and using a slightly modified version of Nicholas Parks Young&amp;rsquo;s &lt;a class=&#34;link&#34; href=&#34;https://github.com/Alarm-Siren/6502-kicad-library&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;6502 KiCad library&lt;/a&gt;, which has saved me a bit of time.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Building a 6502 computer</title>
        <link>https://mike42.me/blog/2021-07-building-a-6502-computer</link>
        <pubDate>Thu, 08 Jul 2021 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2021-07-building-a-6502-computer</guid>
        <description>&lt;p&gt;I&amp;rsquo;ve been using 6502 assembly for some hobby projects recently, but &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective&#34; &gt;only testing in an emulator&lt;/a&gt;. It&amp;rsquo;s about time to target some real hardware, so for the past few weeks I&amp;rsquo;ve been following &lt;a class=&#34;link&#34; href=&#34;https://eater.net/6502&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Ben Eater&amp;rsquo;s 6502 computer tutorial&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-07-building-a-6502-computer/2021-07-6502-computer-1.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-07-building-a-6502-computer/2021-07-6502-computer-1_hu_8b963ee918c83955.jpg 480w, https://mike42.me/blog/2021-07-building-a-6502-computer/2021-07-6502-computer-1_hu_96d1202aec62dbb0.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I am a complete beginner when it comes to electronics, so I spent a bit of time making useless circuits to toggle LED&amp;rsquo;s, then jumped right in to building the simplest possible circuit exercise a 65c02 CPU, &lt;a class=&#34;link&#34; href=&#34;http://retro.hansotten.nl/other-retro-articles/cpu-nop-testers/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;known as a NOP generator&lt;/a&gt;. I used a 555 timer and an inverter to get a 3Hz clock, which is quite a bit slower than my desktop PC.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-07-building-a-6502-computer/2021-07-6502-computer-2.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-07-building-a-6502-computer/2021-07-6502-computer-2_hu_fa67f92cf525e0a3.jpg 480w, https://mike42.me/blog/2021-07-building-a-6502-computer/2021-07-6502-computer-2_hu_5de79a1ce44b0a17.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I then extended the circuit to run NOP instructions from a ROM. I generated a ROM filled with the 6502 NOP instruction by printing a character to a file, then &lt;a class=&#34;link&#34; href=&#34;https://unix.stackexchange.com/a/132071&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;concatenating the file to itself&lt;/a&gt; times to fill the ROM.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ printf &amp;#39;\xEA&amp;#39; &amp;gt; rom-original.bin
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ dd if=rom-original.bin of=rom-original.bin bs=1 seek=1 count=32768
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I am using an open-source tool called &lt;a class=&#34;link&#34; href=&#34;https://gitlab.com/DavidGriffith/minipro&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;minipro&lt;/a&gt; with a TL866II+ programmer to burn the ROM.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ minipro -p AT28C256 -w rom-original.bin
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Found TL866II+ 04.2.86 (0x256)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Warning: Firmware is out of date.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Expected  04.2.123 (0x27b)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Found     04.2.86 (0x256)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Erasing... 0.02Sec OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Protect off...OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Writing Code...  7.44Sec  OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Reading Code...  0.77Sec  OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Verification OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Protect on...OK
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, I tried to extend the circuit to blink some LED&amp;rsquo;s based on a programmed sequence. When I ran the program, the 65c22 I/O chip warmed up, and my row of LED lights did not blink. It turns out that I had mixed up the meaning of VCC and VSS, and applied a reverse voltage to the chip. I &lt;a class=&#34;link&#34; href=&#34;https://www.reddit.com/r/beneater/comments/mp76ra/65c22_chip_causing_voltage_issues_in_6502/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;found a post from somebody else who had made the same mistake&lt;/a&gt;, and corrected it before the chip was damaged.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-07-building-a-6502-computer/2021-07-6502-computer-3.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-07-building-a-6502-computer/2021-07-6502-computer-3_hu_98497d5565dc3188.jpg 480w, https://mike42.me/blog/2021-07-building-a-6502-computer/2021-07-6502-computer-3_hu_e9ebc7e32b5fbd64.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This program worked well initially, but the computer would sometimes crash when running at this slow speed, so I started running it with a 1MHz or 1.8MHz oscillator instead. I now know that this is because I had plugged the 65c02 and 65c22 clock inputs into the 555 timer output, when I should have been running it through the inverter first. The rising-edge and falling-edge times of the 555 timer are apparently not fast enough to clock these chips reliably.&lt;/p&gt;
&lt;p&gt;The next step was to add an LCD and some RAM. My first attempt did not work, and it took me a few hours of troubleshooting to rule out any hardware problems. In the end it was a simple programming error, where I had used a &lt;code&gt;jmp&lt;/code&gt; instruction instead of &lt;code&gt;jsr&lt;/code&gt; in my test program.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-07-building-a-6502-computer/2021-07-6502-computer-4.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2021-07-building-a-6502-computer/2021-07-6502-computer-4_hu_97e98f904bb29fe5.jpg 480w, https://mike42.me/blog/2021-07-building-a-6502-computer/2021-07-6502-computer-4_hu_e49d395dd612fb95.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;So it&amp;rsquo;s not much, but it works! Based on some of the problems that I had while building this, it was definitely a good idea to start with a known-good design on a breadboard.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve got a few ideas (and components) for extending this computer already, and I&amp;rsquo;m hoping to learn a thing or two about hardware and software along the way.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>IntelliJ plugin for 6502 assembly language</title>
        <link>https://mike42.me/blog/2021-05-intellij-plugin-for-6502-assembly-language</link>
        <pubDate>Thu, 27 May 2021 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2021-05-intellij-plugin-for-6502-assembly-language</guid>
        <description>&lt;p&gt;I&amp;rsquo;ve been writing some 6502 assembly code in the past year, and have found the developer experience for this language to be lacking some modern conveniences.&lt;/p&gt;
&lt;p&gt;In my last blog post, I &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective&#34; &gt;described the development tools that I used to implement a simple NES game on Linux&lt;/a&gt;. I used text editor to write the code, and it couldn&amp;rsquo;t do much more than syntax highlighting.&lt;/p&gt;
&lt;p&gt;I write most of my other code in IntelliJ, so I decided to take a look at what would be required to write a plugin for 6502 assembly support. I managed to together something that &lt;em&gt;mostly&lt;/em&gt; works, which I &lt;a class=&#34;link&#34; href=&#34;https://plugins.jetbrains.com/plugin/16799-6502-assembly&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;published to the JetBrains Marketplace&lt;/a&gt; last weekend.&lt;/p&gt;
&lt;p&gt;You can find it by searching &amp;ldquo;6502 Assembly&amp;rdquo; in most JetBrains IDE&amp;rsquo;s.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-05-intellij-plugin-for-6502-assembly-language/2021-05-plugin-page.png&#34;
	width=&#34;1582&#34;
	height=&#34;800&#34;
	srcset=&#34;https://mike42.me/blog/2021-05-intellij-plugin-for-6502-assembly-language/2021-05-plugin-page_hu_c21013988800dcbd.png 480w, https://mike42.me/blog/2021-05-intellij-plugin-for-6502-assembly-language/2021-05-plugin-page_hu_2422e7ee83d2aa2c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;197&#34;
		data-flex-basis=&#34;474px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;features&#34;&gt;Features
&lt;/h2&gt;&lt;p&gt;Firstly, it supports syntax highlighting. I limited the scope of the plugin to &lt;a class=&#34;link&#34; href=&#34;https://cc65.github.io/doc/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;ca65 assembler&lt;/a&gt; syntax only, since it&amp;rsquo;s the assembler that I know best.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-05-intellij-plugin-for-6502-assembly-language/6502_intellij_example.png&#34;
	width=&#34;2258&#34;
	height=&#34;1298&#34;
	srcset=&#34;https://mike42.me/blog/2021-05-intellij-plugin-for-6502-assembly-language/6502_intellij_example_hu_dd76ecbd6827fd13.png 480w, https://mike42.me/blog/2021-05-intellij-plugin-for-6502-assembly-language/6502_intellij_example_hu_a190e53de3ee7c57.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;173&#34;
		data-flex-basis=&#34;417px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;You can navigate to any label with Ctrl+Click. This will not yet work for other types of symbols, such as constants, macros, and imports.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-05-intellij-plugin-for-6502-assembly-language/2021-05-navigate.gif&#34;
	width=&#34;649&#34;
	height=&#34;263&#34;
	
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;246&#34;
		data-flex-basis=&#34;592px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;If the plugin sees a jump or branch statement, and can figure out where the jump goes, then it will show a gutter icon which navigates to the target.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-05-intellij-plugin-for-6502-assembly-language/2021-05-navigate-jump.gif&#34;
	width=&#34;649&#34;
	height=&#34;263&#34;
	
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;246&#34;
		data-flex-basis=&#34;592px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;You can find the usages of a label.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-05-intellij-plugin-for-6502-assembly-language/2021-05-find-usages.gif&#34;
	width=&#34;767&#34;
	height=&#34;375&#34;
	
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;204&#34;
		data-flex-basis=&#34;490px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;In ca65, you can use nested scopes. The plugin shows code folding buttons to collapse these scopes.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-05-intellij-plugin-for-6502-assembly-language/2021-05-expand-code.gif&#34;
	width=&#34;767&#34;
	height=&#34;444&#34;
	
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;172&#34;
		data-flex-basis=&#34;414px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;You can navigate to a symbol by name using the &amp;ldquo;Go To Symbol&amp;rdquo; action.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-05-intellij-plugin-for-6502-assembly-language/2021-05-go-to-symbol.gif&#34;
	width=&#34;767&#34;
	height=&#34;444&#34;
	
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;172&#34;
		data-flex-basis=&#34;414px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The plugin allows for commenting and un-commenting blocks of code, though there is no formatter, so indentation sometimes still has to be fixed manually.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-05-intellij-plugin-for-6502-assembly-language/2021-05-comment-example.gif&#34;
	width=&#34;649&#34;
	height=&#34;263&#34;
	
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;246&#34;
		data-flex-basis=&#34;592px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;It also allows you to rename a label and its usages, which is a great time-saver.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-05-intellij-plugin-for-6502-assembly-language/2021-05-refactor-example.gif&#34;
	width=&#34;1113&#34;
	height=&#34;667&#34;
	
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;166&#34;
		data-flex-basis=&#34;400px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;limitations&#34;&gt;Limitations
&lt;/h2&gt;&lt;p&gt;One limitation is that the plugin does not fully parse expressions, so it will not detect errors from mis-matched brackets.&lt;/p&gt;
&lt;p&gt;Secondly, the plugin does not understand the project structure. This means that if you re-use the same label name in different places in your project, the &amp;ldquo;Rename&amp;rdquo; and &amp;ldquo;Find Usages&amp;rdquo; function will match all of them at once, because it is not smart enough to follow imports and apply scope rules.&lt;/p&gt;
&lt;h2 id=&#34;future-improvements&#34;&gt;Future improvements
&lt;/h2&gt;&lt;p&gt;A lot of things can be done with an IDE plugin, but I&amp;rsquo;m planning to use this initial implementation for a while before attempting to add any big-ticket features.&lt;/p&gt;
&lt;p&gt;A reasonable goal might be to have &amp;ldquo;Hello World&amp;rdquo; project skeletons for common 6502 systems, and to support launching with some common emulators. I would like to be able to set breakpoints and debug 6502 programs in an IDE, but external debugging interfaces are not commonly available for retro emulators, so this is probably not a reasonable goal.&lt;/p&gt;
&lt;p&gt;The code is on GitHub under an MIT license. If you are using this plugin and would like to help improve it, then &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/6502-assembly-intellij&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;pull requests are welcome&lt;/a&gt;.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Building my first NES game: A retrospective</title>
        <link>https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective</link>
        <pubDate>Thu, 22 Apr 2021 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective</guid>
        <description>&lt;p&gt;Last year, I spent a fair amount of time learning how to make games for the Nintendo Entertainment System. The homebrew scene for this system is very much alive, and I was quite proud that I was able to make a simple, working video game which runs on a NES emulator.&lt;/p&gt;
&lt;p&gt;So, I present to you: 8-bit Table Tennis.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective/2021-04-8bit-table-tennis-start-screen.png&#34;
	width=&#34;256&#34;
	height=&#34;224&#34;
	srcset=&#34;https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective/2021-04-8bit-table-tennis-start-screen_hu_2f64b6e6715f9a4f.png 480w, https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective/2021-04-8bit-table-tennis-start-screen_hu_57a3f459d3abdf8a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;114&#34;
		data-flex-basis=&#34;274px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective/2021-04-8bit-table-tennis-gameplay.png&#34;
	width=&#34;256&#34;
	height=&#34;224&#34;
	srcset=&#34;https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective/2021-04-8bit-table-tennis-gameplay_hu_57ca760695eb1909.png 480w, https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective/2021-04-8bit-table-tennis-gameplay_hu_47221be95b413424.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;114&#34;
		data-flex-basis=&#34;274px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This blog post just a few notes about the tools and resources that I used for NES development on Linux, plus a few things that I learned along the way.&lt;/p&gt;
&lt;h2 id=&#34;development-tools&#34;&gt;Development tools
&lt;/h2&gt;&lt;p&gt;The CPU in the NES is a derivative of the once-ubiquitous MOS 6502, and games for it are mostly written in 6502 assembly. I already do a fair amount of programming, but quickly found that my usual editors, compilers and debuggers were useless for this platform.&lt;/p&gt;
&lt;p&gt;The main resources I used were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a class=&#34;link&#34; href=&#34;http://wiki.nesdev.com/w/index.php/Nesdev_Wiki&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Nesdev Wiki&lt;/a&gt; for information about the platform.&lt;/li&gt;
&lt;li&gt;The &lt;a class=&#34;link&#34; href=&#34;http://6502.org/tutorials/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;6502.org tutorials list&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/bbbradsmith/NES-ca65-example&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;This example project&lt;/a&gt; by Brad Smith, which I used as a base.&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.masswerk.at/6502/6502_instruction_set.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;This instruction set reference&lt;/a&gt; - many similar references are available online.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To build my code, I used the &lt;code&gt;cc65&lt;/code&gt; toolchain, which includes a cross-assembler. I did most of my testing in the Nestopia emulator, and most of my programming in Gedit. All three of these are available in the official Debian repositories.&lt;/p&gt;
&lt;h3 id=&#34;gedit-setup&#34;&gt;Gedit setup
&lt;/h3&gt;&lt;p&gt;Out of the box, Gedit can&amp;rsquo;t syntax highlight 6502 assembly. I found a language spec file for it on &lt;a class=&#34;link&#34; href=&#34;http://forum.6502.org/viewtopic.php?t=1690&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;the 6502.org forums&lt;/a&gt;, and edited it slightly before using it.&lt;/p&gt;
&lt;p&gt;At the time of writing, new language specs can be installed on Debian like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo cp asm6502.lang /usr/share/gtksourceview-4/language-specs/asm6502.lang &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo chmod &lt;span class=&#34;m&#34;&gt;0644&lt;/span&gt; /usr/share/gtksourceview-4/language-specs/asm6502.lang
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective/2021-04-6502-assembly-gedit.png&#34;
	width=&#34;2100&#34;
	height=&#34;1368&#34;
	srcset=&#34;https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective/2021-04-6502-assembly-gedit_hu_56132be564509b4b.png 480w, https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective/2021-04-6502-assembly-gedit_hu_b02da5495bd3055f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;153&#34;
		data-flex-basis=&#34;368px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;It is possible to use plugins to add a console and &lt;code&gt;git&lt;/code&gt; support to &lt;code&gt;gedit&lt;/code&gt;, but this is still a long way from a full IDE.&lt;/p&gt;
&lt;h3 id=&#34;geany&#34;&gt;Geany
&lt;/h3&gt;&lt;p&gt;Geany is a programming text editor, and is also available in the official Debian repositories.&lt;/p&gt;
&lt;p&gt;I wasn&amp;rsquo;t able to get it to recognise 6502 assembly, but it does have good x86 assembly (NASM) support, which is similar enough for it to allow navigation through the source code using labels.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective/2021-04-6502-assembly-geany.png&#34;
	width=&#34;2404&#34;
	height=&#34;1642&#34;
	srcset=&#34;https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective/2021-04-6502-assembly-geany_hu_461d20e6d385598b.png 480w, https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective/2021-04-6502-assembly-geany_hu_5b46a970e2e4d5f2.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;146&#34;
		data-flex-basis=&#34;351px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Geany can also set up projects with build scripts (such as a &lt;code&gt;Makefile&lt;/code&gt;), which could allow for faster testing.&lt;/p&gt;
&lt;h3 id=&#34;fceux&#34;&gt;FCEUX
&lt;/h3&gt;&lt;p&gt;FCEUX is a NES emulator which has an in-built debugger, and it runs well under WINE. I was also able to build and run it natively on Linux, but the debugger is only present in the Windows build.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective/2021-04-8bit-table-tennis-fceux.png&#34;
	width=&#34;1267&#34;
	height=&#34;930&#34;
	srcset=&#34;https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective/2021-04-8bit-table-tennis-fceux_hu_c0af8ffd7044061e.png 480w, https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective/2021-04-8bit-table-tennis-fceux_hu_d4a79e75c16103b3.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;136&#34;
		data-flex-basis=&#34;326px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I also briefly experimented with using the FCEUX Lua interface to pause/resume the emulator over a TCP socket for debugging, since that interface is available in the Linux build. I could only pause the emulator between frames, so I decided to abandon this.&lt;/p&gt;
&lt;h2 id=&#34;graphics&#34;&gt;Graphics
&lt;/h2&gt;&lt;p&gt;I created the graphics in the GNU Image Manipulation Program, and manually broke the title page down into tiles.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective/2021-04-8bit-table-tennis-gimp.png&#34;
	width=&#34;2150&#34;
	height=&#34;1912&#34;
	srcset=&#34;https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective/2021-04-8bit-table-tennis-gimp_hu_1fae7132e6924a09.png 480w, https://mike42.me/blog/2021-04-building-my-first-nes-game-a-retrospective/2021-04-8bit-table-tennis-gimp_hu_23be6af3d7157db0.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;112&#34;
		data-flex-basis=&#34;269px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I also wrote a &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/8bit-table-tennis/blob/master/tools/chr_tool.py&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;custom program&lt;/a&gt; to convert a 4-colour PNG file into the native NES CHR graphics format. I run this conversion as part of the build process, so that the graphics files can be stored in a modern format.&lt;/p&gt;
&lt;h2 id=&#34;things-i-learned&#34;&gt;Things I learned
&lt;/h2&gt;&lt;p&gt;Programming for the NES is quite simple once the project is up and running, but even simple tasks can be a real hassle. I spent more time than I expected on mundane tasks such as collision detection, and certainly did a poor job of implementing game physics. The 6502 CPU has no built-in way to multiply, divide, or perform floating point operations. The version used for the NES additionally lacks any way to perform a binary-to-decimal conversion, which would have been &lt;em&gt;very useful&lt;/em&gt; for displaying the player scores! In hindsight, I would have been able to improve the physics by pre-computing some lookup tables.&lt;/p&gt;
&lt;p&gt;On the other hand, I expected it to be difficult to work within 2KiB of RAM, but due to the simplicity of the game, I only used around 25% of it, and had plenty of CHR ROM space leftover as well.&lt;/p&gt;
&lt;p&gt;It took me three weekends to make this project, without having ever written a line of 6502 assembly before. I think that development would be a lot faster if I were able to set breakpoints from my code editor, so I will definitely be looking at other debugging emulators before attempting my next 6502 assembly project.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;8-bit Table Tennis &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/8bit-table-tennis&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;is available as an iNES ROM on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I have only been running it with an emulator, so if any readers of this blog own a flash cartridge for the NES (such as an Everdrive), then please let me know if it works on the real hardware!&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Building a tiny Linux gaming PC</title>
        <link>https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc</link>
        <pubDate>Sun, 31 Jan 2021 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc</guid>
        <description>&lt;p&gt;I recently put together a small form factor PC to use with my TV, with the aim of building a Linux-based, console-like gaming setup. This mostly went to plan, and is certainly a big upgrade from my previous hardware, which &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi&#34; &gt;was based on a retired desktop computer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-01.jpg&#34;
	width=&#34;1024&#34;
	height=&#34;777&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-01_hu_52426c5e42f6db11.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-01_hu_dd260ffd67582333.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;131&#34;
		data-flex-basis=&#34;316px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I am writing a bit about it today, partly because it&amp;rsquo;s been an interesting project, but also to show a working setup for anybody who is attempting something similar.&lt;/p&gt;
&lt;h2 id=&#34;quick-reference&#34;&gt;Quick reference
&lt;/h2&gt;&lt;p&gt;The build is based around these components (PC part picker list &lt;a class=&#34;link&#34; href=&#34;https://au.pcpartpicker.com/list/8Wbf2V&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;here&lt;/a&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In Win Chopin case&lt;/li&gt;
&lt;li&gt;AMD Ryzen 5 3400G CPU&lt;/li&gt;
&lt;li&gt;Gigabyte B450 I AORUS PRO Motherboard&lt;/li&gt;
&lt;li&gt;Noctua NH-L9a-AM4 Cooler&lt;/li&gt;
&lt;li&gt;Corsair Vengeance LPX 16 GB (2x8GB) DDR4-3200 RAM&lt;/li&gt;
&lt;li&gt;Samsung 970 Evo 1 TB&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Peripherals:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sony DualShock 4 controller - Works over Bluetooth and can be used as a touchpad.&lt;/li&gt;
&lt;li&gt;8BitDo SF30 Pro controller - Also works over Bluetooth, and can emulate an Xbox controller.&lt;/li&gt;
&lt;li&gt;Logitech K400R wireless keyboard/mouse&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;hardware-setup&#34;&gt;Hardware setup
&lt;/h2&gt;&lt;p&gt;This is the smallest PC I&amp;rsquo;ve built with desktop parts, and there is not a lot of spare space in the case. I first put everything together on my desk confirm that it would &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Power-on_self-test&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;POST&lt;/a&gt;, then disassembled the case to make some modifications.&lt;/p&gt;
&lt;p&gt;Three screws hold in the power supply, two torx screws hold the aluminium shell to the chassis, and two Phillips-head screws and some tabs hold the plastic front panel cover to the chassis.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-02.jpg&#34;
	width=&#34;1024&#34;
	height=&#34;768&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-02_hu_aa0e396034ef8eb9.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-02_hu_6cb14030a3646469.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-03.jpg&#34;
	width=&#34;1024&#34;
	height=&#34;768&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-03_hu_28c357965ee809c3.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-03_hu_a1d3370c6dd5e210.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The motherboard almost fills the case, and a power supply has to fit in there as well.&lt;/p&gt;
&lt;p&gt;My plan was to route the power cables around the back of the case rather than leaving them in the main cavity. This involved cutting out a square near one of the drive trays for all of the power cables to exit, and another for the ATX power connector to connect to the motherboard. I also removed a metal tab from the power supply, since I had cut out the metal that it was supposed to be screwed to.&lt;/p&gt;
&lt;p&gt;There was an existing hole which I could use for the CPU power connector, which was already the correct size.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-04.jpg&#34;
	width=&#34;768&#34;
	height=&#34;1024&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-04_hu_70a0882a513e014a.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-04_hu_9df7278dc59e6e2e.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;75&#34;
		data-flex-basis=&#34;180px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-05.jpg&#34;
	width=&#34;768&#34;
	height=&#34;1024&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-05_hu_44bc818a1ef582c2.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-05_hu_6bc531d02514545e.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;75&#34;
		data-flex-basis=&#34;180px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-06.jpg&#34;
	width=&#34;768&#34;
	height=&#34;1024&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-06_hu_3520c5bf6eed56af.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-06_hu_cb6dc4eb55e83b02.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;75&#34;
		data-flex-basis=&#34;180px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I then swapped the power supply fan for a Noctua A4x10 PWM so that I could control the fan speed from software. I do not recommend this, since it is unnecessary, and opening a power supply is an electrocution hazard.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-08.jpg&#34;
	width=&#34;1024&#34;
	height=&#34;768&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-08_hu_ba2afe2e46abba8d.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-08_hu_4f6ad5cb76244392.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-09.jpg&#34;
	width=&#34;1024&#34;
	height=&#34;768&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-09_hu_2380bb2d5b5c499e.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-09_hu_f7b6d99db9e07e4f.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-10.jpg&#34;
	width=&#34;1024&#34;
	height=&#34;768&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-10_hu_1108897b3f2c45c8.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-10_hu_9b160c74ebe72640.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Next, I got all of the cables into place, since there is no space to do this after the motherboard is installed&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-11.jpg&#34;
	width=&#34;1024&#34;
	height=&#34;768&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-11_hu_a0bcae5490e5b697.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-11_hu_8d3154ddd7d3fe10.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-12.jpg&#34;
	width=&#34;768&#34;
	height=&#34;1024&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-12_hu_3c0dcce4434bf566.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-12_hu_c5296732318a9538.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;75&#34;
		data-flex-basis=&#34;180px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-13.jpg&#34;
	width=&#34;768&#34;
	height=&#34;1024&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-13_hu_f6071e343e72adf8.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-13_hu_3049da205687950d.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;75&#34;
		data-flex-basis=&#34;180px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Once the power cables were in the right place, I added the motherboard, then connected the front panel I/O, feeding all of the excess cables to the space behind the case. This is a very tight fit, and I accidentally bent the case and squashed some cables before finally getting the plastic front panel to attach.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-14.jpg&#34;
	width=&#34;1024&#34;
	height=&#34;768&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-14_hu_57bfe20479a3846b.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-14_hu_4e00ca6bbea65901.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-15.jpg&#34;
	width=&#34;768&#34;
	height=&#34;1024&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-15_hu_7cfef0b1b2a0686e.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-15_hu_f4bd5fdac931f8c7.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;75&#34;
		data-flex-basis=&#34;180px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-16.jpg&#34;
	width=&#34;1024&#34;
	height=&#34;768&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-16_hu_b653cb5577b57e59.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-16_hu_f7f92428da2cd577.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;After finally lining everything up, I checked that the case closed, and re-attached the shell.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-17.jpg&#34;
	width=&#34;1024&#34;
	height=&#34;768&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-17_hu_66b9e7979b353d56.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-17_hu_2db8b18301ca24b4.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-18.jpg&#34;
	width=&#34;768&#34;
	height=&#34;1024&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-18_hu_edc2062d21801dd8.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-18_hu_e07afe2394157abc.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;75&#34;
		data-flex-basis=&#34;180px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-19.jpg&#34;
	width=&#34;768&#34;
	height=&#34;1024&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-19_hu_858adc97e890bae0.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-19_hu_b10c43feb5f0fe9c.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;75&#34;
		data-flex-basis=&#34;180px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Lastly, I was able to re-fit one of the two drive trays, in case that is ever needed in future.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-20.jpg&#34;
	width=&#34;768&#34;
	height=&#34;1024&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-20_hu_ef3bee678ceee5d8.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-20_hu_9795f5ad9250c796.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;75&#34;
		data-flex-basis=&#34;180px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;bios-setup&#34;&gt;BIOS setup
&lt;/h2&gt;&lt;p&gt;This build uses integrated graphics, so the system memory is also being used as video memory. This means that RAM speed is more important than usual.&lt;/p&gt;
&lt;p&gt;I enabled XMP to run the RAM at its rated 3200 MHz speed. This is higher than the highest officially supported speed of 2933 MHz for this CPU, but for me that was not an issue.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-21.png&#34;
	width=&#34;1024&#34;
	height=&#34;768&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-21_hu_a75c18a097ce93eb.png 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-21_hu_d0e34757860a4e46.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I set the built-in motherboard LED&amp;rsquo;s to blue, to match the default colour on the Sony DualShock 4 controller. This also meant that I would not need to get any RGB software working on Linux.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-22.png&#34;
	width=&#34;1024&#34;
	height=&#34;768&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-22_hu_2c527c5c99c0d3e4.png 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-22_hu_458d78c5a835120c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-23.jpg&#34;
	width=&#34;768&#34;
	height=&#34;1024&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-23_hu_4f07fe6daddfaebe.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-23_hu_3cf327a0abeec19d.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;75&#34;
		data-flex-basis=&#34;180px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Some online sources suggest disabling the AMD Cool &amp;amp; Quiet function to get extra gaming performance, but I consider this advice to be out-dated, unless you&amp;rsquo;re overclocking. Instead, I am leaving this setting enabled, then automatically setting the CPU to &amp;lsquo;performance&amp;rsquo; mode while gaming &lt;a class=&#34;link&#34; href=&#34;https://github.com/FeralInteractive/gamemode&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;via software&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-24.png&#34;
	width=&#34;1024&#34;
	height=&#34;768&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-24_hu_a7b81005db090b43.png 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-24_hu_2aab6cdd71fd954c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Once I got everything working, I disabled everything that I wasn&amp;rsquo;t using, and enabled Ultra Fast Boot. This makes the system start faster, but also removes the ability to re-configure the BIOS, because the keyboard will not work. The settings can be reset via a jumper on the motherboard if I need to get back into it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-25.png&#34;
	width=&#34;1024&#34;
	height=&#34;768&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-25_hu_50d2f5737bb16e93.png 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-25_hu_280e03babf252fed.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;software-setup&#34;&gt;Software setup
&lt;/h2&gt;&lt;p&gt;I installed Ubuntu 20.04 LTS. I would suggest sticking with the Long Term Support version of Ubuntu if you are using it for gaming, since Steam is available in the package manager. Bluetooth, Wi-Fi, sound and 3D-accelerated graphics all worked out of the box.&lt;/p&gt;
&lt;h3 id=&#34;configuring-ubuntu&#34;&gt;Configuring Ubuntu
&lt;/h3&gt;&lt;p&gt;These settings make Ubuntu act less like a desktop, and more like a Home Theater PC.&lt;/p&gt;
&lt;p&gt;First I enabled automatic login, then cleared the password for the login keyring. This avoids needing to use a keyboard on startup, or getting prompted for a password when web browsers attempt to access the keyring.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-26.png&#34;
	width=&#34;1032&#34;
	height=&#34;869&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-26_hu_e9709aa207364e20.png 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-26_hu_1c32b53700056b70.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;118&#34;
		data-flex-basis=&#34;285px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-27.png&#34;
	width=&#34;431&#34;
	height=&#34;264&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-27_hu_64365c3400323fa6.png 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-27_hu_c514f68e002757e6.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;163&#34;
		data-flex-basis=&#34;391px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Under power settings, I set &amp;ldquo;Blank Screen&amp;rdquo; to &amp;ldquo;Never&amp;rdquo;, and Automatic Suspend to &amp;ldquo;Off&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-28.png&#34;
	width=&#34;1060&#34;
	height=&#34;650&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-28_hu_6819313e3be71252.png 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-28_hu_567f509f3eef8daa.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;163&#34;
		data-flex-basis=&#34;391px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Under screen lock settings, I set &amp;ldquo;Blank Screen Delay&amp;rdquo; to &amp;ldquo;Never&amp;rdquo;, and disabled &amp;ldquo;Automatic Screen Lock&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-29.png&#34;
	width=&#34;1060&#34;
	height=&#34;650&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-29_hu_45974e922598d7bb.png 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-29_hu_4368711532627ea.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;163&#34;
		data-flex-basis=&#34;391px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Next, I set the theme to dark mode, the display output to 1920x1080 60Hz, and the audio output device to HDMI. The display is 4K, but compatibility will be challenging enough without adding scaling issues in there, so I&amp;rsquo;m using a lower resolution for now.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-30.png&#34;
	width=&#34;1060&#34;
	height=&#34;650&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-30_hu_bbf842587e92578d.png 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-30_hu_93e94290d88dffa4.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;163&#34;
		data-flex-basis=&#34;391px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Lastly, I set up a tool called &lt;code&gt;psensor&lt;/code&gt; to start on boot, so that I could check temperatures.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-31.png&#34;
	width=&#34;402&#34;
	height=&#34;310&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-31_hu_e3f8eea0e145a697.png 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-31_hu_bd9760c8bef9e5ce.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;129&#34;
		data-flex-basis=&#34;311px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-32.png&#34;
	width=&#34;526&#34;
	height=&#34;530&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-32_hu_1a01654ca5a8893f.png 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-32_hu_afd9783ec03ce96c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;99&#34;
		data-flex-basis=&#34;238px&#34;
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;installing-applications&#34;&gt;Installing applications
&lt;/h3&gt;&lt;p&gt;Linux gaming has advanced a fair bit recently, and since it is a large topic, I won&amp;rsquo;t try to cover in too much detail here. I&amp;rsquo;m connecting this computer up to a TV, so this type of setup is only suitable for games with controller support. Still, this includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Native Linux games.&lt;/li&gt;
&lt;li&gt;Windows games running via a compatibility layer (WINE/DXVK or Proton).&lt;/li&gt;
&lt;li&gt;Games for other systems played through an emulator.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An extensive catalogue is available through the Linux version of Steam, which I installed via the Ubuntu package manager. I could have set Steam to launch on startup and call it a day, but there are two other launchers which I installed alongside it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lutris (from the &lt;code&gt;lutris-team/lutris&lt;/code&gt; PPA).&lt;/li&gt;
&lt;li&gt;Retroarch (from the &lt;code&gt;libretro/testing&lt;/code&gt; PPA)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next, I installed WINE (32 bit and 64 bit), &lt;code&gt;winetricks&lt;/code&gt;, and &lt;code&gt;gamemode&lt;/code&gt; from the Ubuntu package manager, then &lt;a class=&#34;link&#34; href=&#34;https://github.com/GloriousEggroll/proton-ge-custom&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Proton GE&lt;/a&gt; from GitHub. Proton GE is a widely-used Proton fork, which integrates fixes from upstream WINE. This gave me several different run-times for Windows applications, and simply switching between them or adding some environment variables has been sufficient to work around every compatibility issue that I&amp;rsquo;ve encountered so-far.&lt;/p&gt;
&lt;p&gt;Lastly, I installed Kodi from the &lt;code&gt;team-xbmc/ppa&lt;/code&gt; PPA.&lt;/p&gt;
&lt;h2 id=&#34;game-testing&#34;&gt;Game testing
&lt;/h2&gt;&lt;p&gt;For this section, I&amp;rsquo;m listing out a few games from my library that I&amp;rsquo;ve tested. As a quick reminder, this is all running on integrated graphics, on Linux.&lt;/p&gt;
&lt;p&gt;I was mainly checking that I could get a (subjectively) playable frame-rate, and that I could get two controllers to work in local multiplayer where available.&lt;/p&gt;
&lt;h3 id=&#34;steam&#34;&gt;Steam
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;GRIP combat racing&lt;/strong&gt; runs via Proton. It is a fast-paced racing game, has local split-screen multiplayer, and runs very smoothly at 720p.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-33.jpg&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-33_hu_a94a1d6bdf5928f8.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-33_hu_f6994f624778954d.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-34.jpg&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-34_hu_bc4d1640c20f0b2c.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-34_hu_1ea3c04c05139f0d.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Untitled Goose Game&lt;/strong&gt; also runs via Proton. It has recently added a 2-player mode, and runs at 1080p with no hiccups.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-35.jpg&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-35_hu_cac1970125241f11.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-35_hu_537bf754f63a863c.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-36.jpg&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-36_hu_a8b064094ccdf7f8.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-36_hu_70ff9e1031b4d5fc.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Tomb Raider&lt;/strong&gt; reboot is available native for Linux. With low settings, it runs fine at 1080p, with the benchmark indicating a 99 FPS average.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-37.jpg&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-37_hu_c52227b8feb2e58e.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-37_hu_927be4f59724d0b1.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-38.jpg&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-38_hu_cf361f4cad6313f5.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-38_hu_97ee6a55c32c2cae.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shadow of the Tomb Raider&lt;/strong&gt;, also available native for Linux, is a real challenge for this integrated GPU. I am running it at 1080p, lowest settings, though the benchmark comes back with just a 43 FPS average.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-39.jpg&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-39_hu_a8dacd0c94cad2f.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-39_hu_207ab1f8954e0a1f.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-40.jpg&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-40_hu_bed2e88fa3710d3c.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-40_hu_a5ca57c31501eda0.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;lutris&#34;&gt;Lutris
&lt;/h3&gt;&lt;p&gt;Lutris has an Epic Games store installer, which runs the store-front under WINE. I decided to try it out, though it is easily the most buggy software mentioned in this blog post.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-41.jpg&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-41_hu_24171950c1c20f50.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-41_hu_a7d3042a346d898e.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The only game I tested from there was &lt;strong&gt;Rocket League&lt;/strong&gt;. Native Linux support was recently dropped from this title on Steam, but the Windows version from Epic runs just fine on integrated graphics, and has local multiplayer. I run it at 1080p.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-42.jpg&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-42_hu_29a3fc38ebf0b59f.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-42_hu_5339ab63f911c7c.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-43.jpg&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-43_hu_3ed5e4a777bd08d9.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-43_hu_16486a6afc9fbeb6.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I also tested the original &lt;strong&gt;Crysis&lt;/strong&gt; by manually setting up a WINE prefix and adding it to Lutris. I run this at 720p, medium settings. After a few loops, the benchmark indicates that this averages 112 FPS, so I could probably increase the quality or resolution.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-44.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;720&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-44_hu_a0cb5cae3494bed2.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-44_hu_47cda50f33f0a379.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-45.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;720&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-45_hu_25f5ce02a826922c.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-45_hu_de8f3aca46440b52.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I also tested &lt;strong&gt;Crysis 2&lt;/strong&gt; via WINE, which had some concerns about my graphics card. I also run it at 720p, using the &amp;lsquo;Gamer&amp;rsquo; profile. The benchmark indicates that this averages 60 FPS.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-46.png&#34;
	width=&#34;328&#34;
	height=&#34;180&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-46_hu_ef4d57ff051fc098.png 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-46_hu_28eebe097b2256d5.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;182&#34;
		data-flex-basis=&#34;437px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-47.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;720&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-47_hu_830ac4df9c44ad91.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-47_hu_9668d78a65817db1.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-48.jpg&#34;
	width=&#34;1280&#34;
	height=&#34;720&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-48_hu_1a9ae0f829fef1ae.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-48_hu_c25ed90706b17b25.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Super Tux Kart&lt;/strong&gt; is an open source racing game, which can be installed via Lutris. This is a native Linux build, and runs just fine at 1080p. It has controller support and local multiplayer.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-49.jpg&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-49_hu_c377b45413530e18.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-49_hu_c5fc16c298ef5299.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-50.jpg&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-50_hu_53983335b3dc3ab5.jpg 480w, https://mike42.me/blog/2021-01-building-a-tiny-linux-gaming-pc/2021-01-build-50_hu_6a5eb9129efdf443.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap-up
&lt;/h2&gt;&lt;p&gt;This blog post touches on quite a few topics, so I&amp;rsquo;ve left out a lot of the details. If you&amp;rsquo;ve read this far, though, then it&amp;rsquo;s time to talk about down-sides. Some things did not work as planned.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reading/controlling fan speeds did not work from Linux on this Gigabyte motherboard. This has worked so consistently for me on other hardware that I did not even think to check for compatibility here. This means I can only set fan speeds in the BIOS.&lt;/li&gt;
&lt;li&gt;The power supply is noisier than I expected under load. This is due to coil whine, not fan noise.&lt;/li&gt;
&lt;li&gt;When using the 8BitDo SF30 controller over Bluetooth, RetroArch would pause for 10 or 15 seconds at a time. I tracked this down to the fact that I am connecting it as an Xbox controller, and RetroArch was attempting (and failing) to check its battery level. Connecting the controller &lt;em&gt;after&lt;/em&gt; a core has launched avoids the problem.&lt;/li&gt;
&lt;li&gt;I had hoped to run everything under Wayland, but the Epic Games store had terrible graphical glitches. Everything else on this page (Steam, Lutris, Retroarch) worked on Wayland, and this is apparently due to &lt;a class=&#34;link&#34; href=&#34;https://forum.level1techs.com/t/trouble-with-epic-games-store-running-through-wine/149213/4&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;the way that this app uses OpenGL&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This setup works very well for me, and I am glad to be able to show that it&amp;rsquo;s possible to do some basic gaming without Microsoft Windows or a dedicated GPU. Still, there are a lot of trade-offs that come from this form-factor and platform, and that&amp;rsquo;s not for everybody.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to auto-scale the display in GNOME Boxes</title>
        <link>https://mike42.me/blog/2019-08-how-to-auto-scale-the-display-in-gnome-boxes</link>
        <pubDate>Thu, 22 Aug 2019 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2019-08-how-to-auto-scale-the-display-in-gnome-boxes</guid>
        <description>&lt;p&gt;I recently installed a virtual machine in GNOME Boxes, and the display was stuck at 1024x768.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-08-how-to-auto-scale-the-display-in-gnome-boxes/2019-08-gnome-boxes-01.png&#34;
	width=&#34;1926&#34;
	height=&#34;1220&#34;
	srcset=&#34;https://mike42.me/blog/2019-08-how-to-auto-scale-the-display-in-gnome-boxes/2019-08-gnome-boxes-01_hu_8e6aa5ea007536f8.png 480w, https://mike42.me/blog/2019-08-how-to-auto-scale-the-display-in-gnome-boxes/2019-08-gnome-boxes-01_hu_4851939ae3de5db1.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;157&#34;
		data-flex-basis=&#34;378px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The type of display used here is called SPICE, and it includes a channel for auto-scaling. The guest simply needs the agent to be installed.&lt;/p&gt;
&lt;p&gt;In this case, I&amp;rsquo;m running a Debian guest, which means that I must have forgotten to install the &lt;code&gt;spice-vdagent&lt;/code&gt; package.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# apt-get install spice-vdagent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Reading package lists... Done
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Building dependency tree       
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Reading state information... Done
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;The following NEW packages will be installed:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  spice-vdagent
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; upgraded, &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; newly installed, &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; to remove and &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; not upgraded.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Need to get 47.6 kB of archives.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;After this operation, &lt;span class=&#34;m&#34;&gt;174&lt;/span&gt; kB of additional disk space will be used.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Get:1 http://deb.debian.org/debian buster/main amd64 spice-vdagent amd64 0.18.0-1 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;47.6 kB&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Fetched 47.6 kB in 0s &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;99.9 kB/s&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Selecting previously unselected package spice-vdagent.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;Reading database ... &lt;span class=&#34;m&#34;&gt;132855&lt;/span&gt; files and directories currently installed.&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Preparing to unpack .../spice-vdagent_0.18.0-1_amd64.deb ...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Unpacking spice-vdagent &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;0.18.0-1&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Setting up spice-vdagent &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;0.18.0-1&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Created symlink /etc/systemd/system/sockets.target.wants/spice-vdagentd.socket → /lib/systemd/system/spice-vdagentd.socket.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;spice-vdagentd.conf:2&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Line references path below legacy directory /var/run/, updating /var/run/spice-vdagentd → /run/spice-vdagentd&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; please update the tmpfiles.d/ drop-in file accordingly.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Processing triggers &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; man-db &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;2.8.5-2&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Processing triggers &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; systemd &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;241-5&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The easiest way to ensure that everything is running correctly is to reboot the guest, since the agent will start on boot, and this also forces a new log-in, as well as a new connection to the display.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# reboot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;result&#34;&gt;Result
&lt;/h2&gt;&lt;p&gt;Assuming that you are otherwise on the default settings, the display in the guest VM will now automatically adjust as you resize the window.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-08-how-to-auto-scale-the-display-in-gnome-boxes/2019-08-gnome-boxes-02.png&#34;
	width=&#34;2812&#34;
	height=&#34;1062&#34;
	srcset=&#34;https://mike42.me/blog/2019-08-how-to-auto-scale-the-display-in-gnome-boxes/2019-08-gnome-boxes-02_hu_c3ecfd97314a25cc.png 480w, https://mike42.me/blog/2019-08-how-to-auto-scale-the-display-in-gnome-boxes/2019-08-gnome-boxes-02_hu_ab7c348e8c85a8b2.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;264&#34;
		data-flex-basis=&#34;635px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;If the &amp;ldquo;Share Clipboard&amp;rdquo; setting is enabled for the virtual machine, then &lt;code&gt;spice-vdagent&lt;/code&gt; will also enable you to copy &amp;amp; paste text between the host and guest.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to use the qemu-bridge-helper on Debian 10</title>
        <link>https://mike42.me/blog/2019-08-how-to-use-the-qemu-bridge-helper-on-debian-10</link>
        <pubDate>Thu, 08 Aug 2019 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2019-08-how-to-use-the-qemu-bridge-helper-on-debian-10</guid>
        <description>&lt;p&gt;If you use the &lt;code&gt;libvirt&lt;/code&gt; virtualisation libraries, then you will be familiar with the &amp;ldquo;user session&amp;rdquo;. This feature lets you provision virtual machines to run under a regular, unprivileged user account.&lt;/p&gt;
&lt;p&gt;The user session is used by GNOME Boxes, and can also be managed from Virtual Machine Manager.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-08-how-to-use-the-qemu-bridge-helper-on-debian-10/2019-08-qemu-networking-01.png&#34;
	width=&#34;1956&#34;
	height=&#34;1242&#34;
	srcset=&#34;https://mike42.me/blog/2019-08-how-to-use-the-qemu-bridge-helper-on-debian-10/2019-08-qemu-networking-01_hu_543b881adc900dc.png 480w, https://mike42.me/blog/2019-08-how-to-use-the-qemu-bridge-helper-on-debian-10/2019-08-qemu-networking-01_hu_b01c8a2c11301b42.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;157&#34;
		data-flex-basis=&#34;377px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The main downside to this setup is that a regular user can only access a very limited range of networking options. The &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/libvirt-migrate-a-vm-from-qemusession-to-qemusystem&#34; &gt;last time that I mentioned this in a blog post&lt;/a&gt;, a reader pointed out that you can actually use &lt;code&gt;qemu-bridge-helper&lt;/code&gt; to provide bridged networking to unprivileged virtual machines.&lt;/p&gt;
&lt;p&gt;Today I finally tried this out, and it worked really well. With a bit of configuration, you can extend proper networking to this type of VM.&lt;/p&gt;
&lt;h2 id=&#34;the-host&#34;&gt;The host
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;m running a graphical Debian 10 desktop, with a few basic virtualisation packages.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gnome-boxes&lt;/code&gt; for creating VM&amp;rsquo;s as a local user. This depends on &lt;code&gt;libvirt-daemon&lt;/code&gt;, which is enough to host VM&amp;rsquo;s on the system.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;virt-manager&lt;/code&gt; for a more advanced graphical interface.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The tool that I&amp;rsquo;m writing about today is &lt;code&gt;qemu-bridge-helper&lt;/code&gt;, which is in the &lt;code&gt;qemu-system-common&lt;/code&gt; package.&lt;/p&gt;
&lt;p&gt;After installation, you will also need to ensure that &lt;code&gt;libvirtd&lt;/code&gt; is running.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ systemctl &lt;span class=&#34;nb&#34;&gt;enable&lt;/span&gt; libvirtd.service
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ systemctl start libvirtd.service
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;set-up-a-bridge&#34;&gt;Set up a bridge
&lt;/h2&gt;&lt;p&gt;Libvirt ships with a basic network bridge configuration, you just need to enable it.&lt;/p&gt;
&lt;h3 id=&#34;command-line-method&#34;&gt;Command-line method
&lt;/h3&gt;&lt;p&gt;Start the &lt;code&gt;default&lt;/code&gt; network bridge, and configure it to run on startup.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo virsh net-autostart --network default
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo virsh net-start --network default
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once this is set up, you should see the bridge &lt;code&gt;virbr0&lt;/code&gt;, reporting the IP range &lt;code&gt;192.168.122.1/24&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ip addr show virbr0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;3: virbr0: &amp;lt;NO-CARRIER,BROADCAST,MULTICAST,UP&amp;gt; mtu &lt;span class=&#34;m&#34;&gt;1500&lt;/span&gt; qdisc noqueue state DOWN group default qlen &lt;span class=&#34;m&#34;&gt;1000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       valid_lft forever preferred_lft forever
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;graphical-method&#34;&gt;Graphical method
&lt;/h3&gt;&lt;p&gt;First, open up &lt;strong&gt;Virtual Machine Manager&lt;/strong&gt;, and authenticate. Right click on &lt;strong&gt;QEMU/KVM&lt;/strong&gt;, and select &lt;strong&gt;Details&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Under &lt;strong&gt;Virtual Networks&lt;/strong&gt; → &lt;strong&gt;default&lt;/strong&gt; → &lt;strong&gt;Autostart&lt;/strong&gt;, check &lt;strong&gt;On Boot&lt;/strong&gt;, then click Apply.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-08-how-to-use-the-qemu-bridge-helper-on-debian-10/2019-08-qemu-networking-02.png&#34;
	width=&#34;1920&#34;
	height=&#34;1434&#34;
	srcset=&#34;https://mike42.me/blog/2019-08-how-to-use-the-qemu-bridge-helper-on-debian-10/2019-08-qemu-networking-02_hu_a69a048276b31bcd.png 480w, https://mike42.me/blog/2019-08-how-to-use-the-qemu-bridge-helper-on-debian-10/2019-08-qemu-networking-02_hu_cc0e9a556292260e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;321px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;setting-up-qemu-bridge-helper&#34;&gt;Setting up qemu-bridge-helper
&lt;/h2&gt;&lt;p&gt;Create the file &lt;code&gt;/etc/qemu/bridge.conf&lt;/code&gt; with the content:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;allow virbr0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Restrict the permissions of this file to make sure it can&amp;rsquo;t be edited by regular users.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# chown root:root /etc/qemu/bridge.conf
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# chmod 0640 /etc/qemu/bridge.conf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add &lt;code&gt;setuid&lt;/code&gt; to the &lt;code&gt;qemu-bridge-helper&lt;/code&gt; binary.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# chmod u+s /usr/lib/qemu/qemu-bridge-helper
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you do not correctly set this last step, then you will receive the following error when you attempt to connect a VM to the bridge:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Error starting domain: internal error: /usr/lib/qemu/qemu-bridge-helper --use-vnet --br=virbr0 --fd=28: failed to communicate with bridge helper: Transport endpoint is not connected
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;stderr=failed to create tun device: Operation not permitted
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;setting-up-the-vm&#34;&gt;Setting up the VM
&lt;/h2&gt;&lt;p&gt;Create a virtual machine, either though GNOME Boxes or Virtual Machine Manager. I am using a CentOS VM as an example here, but the guest platform is not particularly important.&lt;/p&gt;
&lt;p&gt;Using Virtual Machine Manage, change the network card to the &amp;ldquo;shared network&amp;rdquo; &lt;code&gt;virbr0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-08-how-to-use-the-qemu-bridge-helper-on-debian-10/2019-08-qemu-networking-03.png&#34;
	width=&#34;1802&#34;
	height=&#34;1138&#34;
	srcset=&#34;https://mike42.me/blog/2019-08-how-to-use-the-qemu-bridge-helper-on-debian-10/2019-08-qemu-networking-03_hu_d484bbec9c078630.png 480w, https://mike42.me/blog/2019-08-how-to-use-the-qemu-bridge-helper-on-debian-10/2019-08-qemu-networking-03_hu_5ab0fdcbf74cbea.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;158&#34;
		data-flex-basis=&#34;380px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The graphical configuration above is equivalent to the following &lt;code&gt;libvirt&lt;/code&gt; domain XML, as below.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;&amp;lt;interface&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;bridge&amp;#39;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;mac&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;address=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;52:54:00:08:5a:7c&amp;#39;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;source&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;bridge=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;virbr0&amp;#39;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;model&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;virtio&amp;#39;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;address&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;pci&amp;#39;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;domain=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;0x0000&amp;#39;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;bus=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;0x00&amp;#39;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;slot=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;0x03&amp;#39;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;function=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;0x0&amp;#39;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;&amp;lt;/interface&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;result&#34;&gt;Result
&lt;/h2&gt;&lt;p&gt;After restarting the network interface in the guest, I was able to ping the the guest from the host and vice versa.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-08-how-to-use-the-qemu-bridge-helper-on-debian-10/2019-08-qemu-networking-04-1.png&#34;
	width=&#34;2730&#34;
	height=&#34;1458&#34;
	srcset=&#34;https://mike42.me/blog/2019-08-how-to-use-the-qemu-bridge-helper-on-debian-10/2019-08-qemu-networking-04-1_hu_14b40998bcdd8c78.png 480w, https://mike42.me/blog/2019-08-how-to-use-the-qemu-bridge-helper-on-debian-10/2019-08-qemu-networking-04-1_hu_c0e1c5a487865b90.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;187&#34;
		data-flex-basis=&#34;449px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This is a significant improvement from &amp;ldquo;user-mode&amp;rdquo; networking, which does not facilitate host-to-guest and guest-to-guest communication.&lt;/p&gt;
&lt;p&gt;The default &lt;code&gt;virbr0&lt;/code&gt; bridge uses an internal subnet, so the guest here is still inaccessible from the wider LAN. If this doesn&amp;rsquo;t match your setup, then you can use the same technique to connect unprivileged virtual machines to another bridge of your choice.&lt;/p&gt;
&lt;h2 id=&#34;further-reading&#34;&gt;Further reading
&lt;/h2&gt;&lt;p&gt;I had to adapt some paths, user accounts and package names to get this working on Debian. The sources I used are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://unix.stackexchange.com/questions/391347/what-is-the-actual-default-networking-type-in-gnome-boxes-using-qemu-session/391586#391586&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;This answer on Unix StackExchange&lt;/a&gt; &amp;ndash; found &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/libvirt-migrate-a-vm-from-qemusession-to-qemusystem#comment-1211&#34; &gt;here&lt;/a&gt; (thank you Fouad!)&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://wiki.qemu.org/Features/HelperNetworking&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;QEMU Wiki: Features/HelperNetworking&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>Benchmarking PHP code with PhpBench</title>
        <link>https://mike42.me/blog/2019-07-benchmarking-php-code-with-phpbench</link>
        <pubDate>Thu, 04 Jul 2019 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2019-07-benchmarking-php-code-with-phpbench</guid>
        <description>&lt;p&gt;This blog post is all about measuring the speed of PHP code through micro-benchmarks.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-07-benchmarking-php-code-with-phpbench/2019-06-phpbench04.png&#34;
	width=&#34;1359&#34;
	height=&#34;319&#34;
	srcset=&#34;https://mike42.me/blog/2019-07-benchmarking-php-code-with-phpbench/2019-06-phpbench04_hu_1871c52098b73a5e.png 480w, https://mike42.me/blog/2019-07-benchmarking-php-code-with-phpbench/2019-06-phpbench04_hu_af76e5f1ca292c9e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;426&#34;
		data-flex-basis=&#34;1022px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;why-micro-benchmarks&#34;&gt;Why micro-benchmarks
&lt;/h2&gt;&lt;p&gt;I think of micro-benchmarks as a complement to tests. A well-written test would give a developer a definite pass or fail result, while well-written micro-benchmark will give the developer an indication of the duration of an operation.&lt;/p&gt;
&lt;p&gt;To put it another way, tests can help you find out whether the code is behaving correctly, while micro-benchmarks can help you to track whether your changes are making the code faster or slower.&lt;/p&gt;
&lt;p&gt;Make sure that your code is doing real processing work before you spend time on this: Algorithms such as sorting, compressing, or parsing are good candidates. My guess is that most of the code in a regular PHP application would not benefit significantly from having a suite of benchmarks, because web apps tend to be I/O bound (eg database, network and disk access).&lt;/p&gt;
&lt;h2 id=&#34;introducing-phpbench&#34;&gt;Introducing PhpBench
&lt;/h2&gt;&lt;p&gt;I have previously written a standalone test script every time I&amp;rsquo;ve needed to measure the speed of something in PHP. This works up to a point, but it gets quite hard to maintain as the number of benchmarks increases.&lt;/p&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/phpbench/phpbench&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;PhpBench&lt;/a&gt; is one of the available tools for running micro-benchmarks from PHP, and there are a few reasons why I think it&amp;rsquo;s worth a try:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;it&amp;rsquo;s actively maintained&lt;/li&gt;
&lt;li&gt;it installs with &lt;code&gt;composer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;it runs in a similar way to PHPUnit, so the benchmarks are fully specified in PHP code and run with a PHP tool.&lt;/li&gt;
&lt;li&gt;it implements familiar concepts that you would find in benchmarking tools from other languages (eg. &lt;a class=&#34;link&#34; href=&#34;https://openjdk.java.net/projects/code-tools/jmh/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;JMH&lt;/a&gt; from the Java world).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation
&lt;/h2&gt;&lt;p&gt;Start out with a blank composer project.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ composer init
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add some auto-loading settings to &lt;code&gt;composer.yml&lt;/code&gt; that PHP knows to find &lt;code&gt;ExampleApp&lt;/code&gt; classes in the &lt;code&gt;src&lt;/code&gt; folder.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;mike42/php-benchmark-examples&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Example PHP benchmark project&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;project&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;license&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;MIT&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;minimum-stability&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;dev&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;require&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;require-dev&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;autoload&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;psr-4&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nt&#34;&gt;&amp;#34;ExampleApp\\&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;src&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At this point, install the &lt;code&gt;phpbench&lt;/code&gt; dev version.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ composer require --dev phpbench/phpbench:@dev
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./composer.json has been updated
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loading composer repositories with package information
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Updating dependencies &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;including require-dev&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Package operations: &lt;span class=&#34;m&#34;&gt;22&lt;/span&gt; installs, &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; updates, &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; removals
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing symfony/process &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;4.4.x-dev 1a42849&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: Cloning 1a42849a7f from cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing symfony/options-resolver &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;4.4.x-dev 94cbb72&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: Cloning 94cbb72bb9 from cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing symfony/finder &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;4.4.x-dev 1b5ec12&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: Cloning 1b5ec12340 from cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing symfony/polyfill-ctype &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;dev-master 82ebae0&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: Cloning 82ebae0220 from cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing symfony/filesystem &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;4.4.x-dev 5914824&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: Cloning 59148241f7 from cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing psr/log &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;dev-master c4421fc&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: Cloning c4421fcac1 from cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing symfony/debug &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;4.4.x-dev 8278839&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: Cloning &lt;span class=&#34;m&#34;&gt;8278839457&lt;/span&gt; from cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing symfony/service-contracts &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;dev-master 0c81a04&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: Cloning 0c81a04f68 from cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing symfony/polyfill-php73 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;dev-master d1fb4ab&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: Cloning d1fb4abcc0 from cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing symfony/polyfill-mbstring &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;dev-master fe5e94c&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: Cloning fe5e94c604 from cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing symfony/console &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;4.4.x-dev e2fe100&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: Cloning e2fe1002fd from cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing lstrojny/functional-php &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;1.9.0&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: Loading from cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing beberlei/assert &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;v3.x-dev ce139b6&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: Cloning ce139b6bf8 from cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing seld/jsonlint &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;1.7.1&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: Loading from cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing psr/container &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;dev-master 014d250&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: Cloning 014d250dae from cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing phpbench/container &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;1.2&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: Loading from cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing webmozart/assert &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;1.4.0&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: Loading from cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing webmozart/path-util &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;dev-master 95a8f7a&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: Cloning 95a8f7ad15 from cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing phpbench/dom &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;0.2.0&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: Loading from cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing doctrine/lexer &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;dev-master ee614dd&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: Cloning ee614dd93a from cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing doctrine/annotations &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;1.7.x-dev 3f35255&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: Cloning 3f35255290 from cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing phpbench/phpbench &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;dev-master dccc67d&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: Cloning dccc67dd52 from cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;symfony/service-contracts suggests installing symfony/service-implementation
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;symfony/console suggests installing symfony/event-dispatcher
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;symfony/console suggests installing symfony/lock
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Writing lock file
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Generating autoload files
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;writing-a-benchmark&#34;&gt;Writing a benchmark
&lt;/h2&gt;&lt;p&gt;Add some code to &lt;code&gt;src/ExampleThing.php&lt;/code&gt; to measure.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;namespace&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ExampleApp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;ExampleThing&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;   * Inefficiently multiply numbers together
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;   */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;multiply&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$y&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$j&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$j&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$y&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$j&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$ret&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Write a benchmark for the code in &lt;code&gt;benchmarks/ExampleThingBenchmark.php&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ExampleApp\ExampleThing&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * @BeforeMethods({&amp;#34;init&amp;#34;})
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * @Revs(1000)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * @Iterations(5)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;ExampleThingBenchmark&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;private&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$exampleThing&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$exampleThing&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ExampleThing&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;     * @Subject
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;doMultiply&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$exampleThing&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;multiply&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Before you run anything, you will also need a configuration file. Add this minimal configuration to &lt;code&gt;phpbench.json.dist&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;php_disable_ini&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;bootstrap&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;vendor/autoload.php&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;path&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;benchmark&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;php_config&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;extension&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;json.so&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;time_unit&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;milliseconds&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;running-the-benchmark&#34;&gt;Running the benchmark
&lt;/h2&gt;&lt;p&gt;The most basic way to run all benchmarks at once is &lt;code&gt;phpbench run&lt;/code&gt;, which looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ php vendor/bin/phpbench run
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PhpBench @git_tag@. Running benchmarks.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Using configuration file: /home/mike/workspace/blog/phpbench/php-benchmarks/phpbench.json.dist
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;\ExampleThingBenchmark
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    doMultiply..............................I4 [μ Mo]/r: 0.232 0.232 (ms) [μSD μRSD]/r: 0.000ms 0.10%
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;1 subjects, 5 iterations, 1,000 revs, 0 rejects, 0 failures, 0 warnings
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(best [mean mode] worst) = 0.232 [0.232 0.232] 0.233 (ms)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;⅀T: 1.162ms μSD/r 0.000ms μRSD/r: 0.100%
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you might expect, there are options to run specific benchmarks, or to present the results in different ways. However, there were some PhpBench-specific things which you will need to navigate to use it successfully.&lt;/p&gt;
&lt;p&gt;Firstly, there are two different output settings to consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;report&lt;/code&gt; options allow you to decide which data to print in a table.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;output&lt;/code&gt; options allow you to decide how to format it for output&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also found it useful to add &lt;code&gt;--progress=none&lt;/code&gt; to suppress the text displayed by default, since you will otherwise get broken HTML output.&lt;/p&gt;
&lt;p&gt;Lastly, be aware that confusingly, the &lt;code&gt;default&lt;/code&gt; report is not active by default. Specify it to get a table listing out each iteration.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ php vendor/bin/phpbench run --progress=none --report=default
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;suite: 13415431dc0db41c12decee0fa83c26d1db0f678, date: 2019-05-31, stime: 22:01:34
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+-----------------------+------------+-----+------+------+----------+-----------+--------------+----------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;| benchmark             | subject    | set | revs | iter | mem_peak | time_rev  | comp_z_value | comp_deviation |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+-----------------------+------------+-----+------+------+----------+-----------+--------------+----------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;| ExampleThingBenchmark | doMultiply | 0   | 1000 | 0    | 915,736b | 236.716μs | +1.68σ       | +1.08%         |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;| ExampleThingBenchmark | doMultiply | 0   | 1000 | 1    | 915,736b | 231.999μs | -1.45σ       | -0.93%         |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;| ExampleThingBenchmark | doMultiply | 0   | 1000 | 2    | 915,736b | 233.960μs | -0.15σ       | -0.1%          |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;| ExampleThingBenchmark | doMultiply | 0   | 1000 | 3    | 915,736b | 233.878μs | -0.2σ        | -0.13%         |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;| ExampleThingBenchmark | doMultiply | 0   | 1000 | 4    | 915,736b | 234.361μs | +0.12σ       | +0.08%         |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+-----------------------+------------+-----+------+------+----------+-----------+--------------+----------------+
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The type of report that I found most useful is &lt;code&gt;aggregate&lt;/code&gt;, since it provides a summary of each iteration.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ php vendor/bin/phpbench run --progress=none --report=aggregate
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;suite: 1341543c02ebee4031d165665c2724c379bf9c98, date: 2019-05-31, stime: 22:01:18
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+-----------------------+------------+-----+------+-----+----------+-----------+-----------+-----------+-----------+---------+--------+-------+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;| benchmark             | subject    | set | revs | its | mem_peak | best      | mean      | mode      | worst     | stdev   | rstdev | diff  |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+-----------------------+------------+-----+------+-----+----------+-----------+-----------+-----------+-----------+---------+--------+-------+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;| ExampleThingBenchmark | doMultiply | 0   | 1000 | 5   | 915,736b | 231.907μs | 232.614μs | 232.089μs | 233.538μs | 0.713μs | 0.31%  | 1.00x |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+-----------------------+------------+-----+------+-----+----------+-----------+-----------+-----------+-----------+---------+--------+-------+
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Both of the example above use &lt;code&gt;console&lt;/code&gt; output, which is the default.&lt;/p&gt;
&lt;h2 id=&#34;html-reports&#34;&gt;HTML reports
&lt;/h2&gt;&lt;p&gt;To capture &lt;code&gt;phpbench&lt;/code&gt; output from a CI environment, you can generate a HTML report  as well. Add an &lt;code&gt;output&lt;/code&gt; section to &lt;code&gt;phpbench.json.dist&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;err&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;outputs&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;nt&#34;&gt;&amp;#34;html_file&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             &lt;span class=&#34;nt&#34;&gt;&amp;#34;extends&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;html&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             &lt;span class=&#34;nt&#34;&gt;&amp;#34;file&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;benchmarks.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             &lt;span class=&#34;nt&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Example benchmark report&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This new &lt;code&gt;html_file&lt;/code&gt; output can be used with &lt;code&gt;--output=html_file&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ php vendor/bin/phpbench run &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --progress&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;none --report&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;aggregate &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    --output&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;console --output&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;html_file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;from-jenkins&#34;&gt;From Jenkins
&lt;/h2&gt;&lt;p&gt;This is a &lt;code&gt;Jenkinsfile&lt;/code&gt; that I use to run benchmarks. You need to install the &amp;ldquo;HTML Publisher&amp;rdquo; and &amp;ldquo;AnsiColor&amp;rdquo; Jenkins plugins.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pipeline &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  agent any
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  stages &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    stage&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Install&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      steps &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        ansiColor&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;xterm&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          sh &lt;span class=&#34;s1&#34;&gt;&amp;#39;composer install&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    stage&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Run benchmarks&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      steps &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        ansiColor&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;xterm&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          sh &lt;span class=&#34;s1&#34;&gt;&amp;#39;php vendor/bin/phpbench run --progress=none --report aggregate --output=console --output=html_file --ansi&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          publishHTML&lt;span class=&#34;o&#34;&gt;([&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            allowMissing: false,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            alwaysLinkToLastBuild: true,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            keepAll: true,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            reportDir: &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            reportFiles: &lt;span class=&#34;s1&#34;&gt;&amp;#39;benchmarks.html&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            reportName:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;s1&#34;&gt;&amp;#39;phpbench report&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            reportTitles: &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;o&#34;&gt;])&lt;/span&gt;       
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Each build is then benchmarked, and the results are available as a link on the left.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-07-benchmarking-php-code-with-phpbench/2019-06-phpbench02.png&#34;
	width=&#34;1391&#34;
	height=&#34;497&#34;
	srcset=&#34;https://mike42.me/blog/2019-07-benchmarking-php-code-with-phpbench/2019-06-phpbench02_hu_b8e8d05b615a3673.png 480w, https://mike42.me/blog/2019-07-benchmarking-php-code-with-phpbench/2019-06-phpbench02_hu_b62886335ff8dea9.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;279&#34;
		data-flex-basis=&#34;671px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The console output of the build shows the results.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-07-benchmarking-php-code-with-phpbench/2019-06-phpbench01.png&#34;
	width=&#34;1468&#34;
	height=&#34;415&#34;
	srcset=&#34;https://mike42.me/blog/2019-07-benchmarking-php-code-with-phpbench/2019-06-phpbench01_hu_faf7f9324303a85f.png 480w, https://mike42.me/blog/2019-07-benchmarking-php-code-with-phpbench/2019-06-phpbench01_hu_6df9979f92102a07.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;353&#34;
		data-flex-basis=&#34;848px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;To actually view the HTML report you will need to apply &lt;a class=&#34;link&#34; href=&#34;https://stackoverflow.com/a/37623540/1808534&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this tweak&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-07-benchmarking-php-code-with-phpbench/2019-06-phpbench03.png&#34;
	width=&#34;1350&#34;
	height=&#34;428&#34;
	srcset=&#34;https://mike42.me/blog/2019-07-benchmarking-php-code-with-phpbench/2019-06-phpbench03_hu_e11aa49988780614.png 480w, https://mike42.me/blog/2019-07-benchmarking-php-code-with-phpbench/2019-06-phpbench03_hu_ef9de143cba33647.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;315&#34;
		data-flex-basis=&#34;757px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next steps
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;ve started to add &lt;code&gt;phpbench&lt;/code&gt; micro-benchmarks to some PHP projects that I work on, and I&amp;rsquo;m finding it a lot more useful than standalone test scripts.&lt;/p&gt;
&lt;p&gt;The next step would be to integrate micro-benchmarks better into the development process. For example, I can already review code coverage improvements/regressions of a change on GitHub using Coveralls, which posts a comment to each pull request. This saves you from merging changes which don&amp;rsquo;t meet your project&amp;rsquo;s standards.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-07-benchmarking-php-code-with-phpbench/2019-06-codecov.png&#34;
	width=&#34;1227&#34;
	height=&#34;534&#34;
	srcset=&#34;https://mike42.me/blog/2019-07-benchmarking-php-code-with-phpbench/2019-06-codecov_hu_f26d214590006f2d.png 480w, https://mike42.me/blog/2019-07-benchmarking-php-code-with-phpbench/2019-06-codecov_hu_9b2a296343a40477.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;229&#34;
		data-flex-basis=&#34;551px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;As far as I can tell, you would need to write custom code for more expressive &lt;code&gt;phpbench&lt;/code&gt; reports along these lines, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the history of a benchmark over time, or&lt;/li&gt;
&lt;li&gt;the most-changed benchmarks against a baseline&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;phpbench&lt;/code&gt; does provide the building-blocks though, since you can set some options to archive the results of each run to a folder.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to integrate Gitea and Jenkins</title>
        <link>https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins</link>
        <pubDate>Thu, 30 May 2019 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins</guid>
        <description>&lt;p&gt;Gitea is a web app for hosting Git repositories. It&amp;rsquo;s open source, and very simple to get running. With some extra setup, it can also trigger Jenkins builds, and display the Jenkins build status of each commit once it has been built.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-20.png&#34;
	width=&#34;2434&#34;
	height=&#34;1274&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-20_hu_c790e9427e83e6be.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-20_hu_e57e092c45e43831.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;191&#34;
		data-flex-basis=&#34;458px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Because the documentation for the Jenkins plugin is &lt;a class=&#34;link&#34; href=&#34;https://github.com/jenkinsci/gitea-plugin/tree/7569bb8d7e7c94841a78a76500ef000cdebc95f5/docs&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;very minimalist&lt;/a&gt;, I decided to write about it for future reference.&lt;/p&gt;
&lt;h2 id=&#34;about-this-setup&#34;&gt;About this setup
&lt;/h2&gt;&lt;p&gt;I installed Jenkins and Gitea on the same Debian 9 server on the LAN. They communicate only over HTTP, so they could just as easily be installed separately.&lt;/p&gt;
&lt;p&gt;To make the configuration clear, I&amp;rsquo;ve used &lt;code&gt;jenkins.example.com&lt;/code&gt; in URLs which refer to Jenkins, and &lt;code&gt;gitea.example.com&lt;/code&gt; for the Gitea.&lt;/p&gt;
&lt;h2 id=&#34;gitea-installation&#34;&gt;Gitea installation
&lt;/h2&gt;&lt;p&gt;This command will install and start the &lt;code&gt;linux-amd64&lt;/code&gt; version of Gitea as the user &amp;ldquo;git&amp;rdquo;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;useradd git -r --create-home &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  mkdir /opt/gitea &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; chown -R git: /opt/gitea &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  wget -O /opt/gitea/gitea https://dl.gitea.io/gitea/1.7.0/gitea-1.7.0-linux-amd64 &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  chmod +x /opt/gitea/gitea &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  sudo -u git bash -c &lt;span class=&#34;s2&#34;&gt;&amp;#34;cd /opt/gitea &amp;amp;&amp;amp; ./gitea web&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Shut it down, and configure some paths at &lt;code&gt;/opt/gitea/custom/conf/app.ini&lt;/code&gt;. These will depend on your environment.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;SSH_DOMAIN&lt;/span&gt;       &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; gitea.example.com
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;DOMAIN&lt;/span&gt;           &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; gitea.example.com
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;HTTP_PORT&lt;/span&gt;        &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;ROOT_URL&lt;/span&gt;         &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; http://gitea.example.com:3000/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Start it back up as a &lt;code&gt;systemd&lt;/code&gt; service at this point, by creating &lt;code&gt;/etc/systemd/system/gitea.service&lt;/code&gt; with this content:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;[Unit]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;Description&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;gitea&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;After&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;network.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;[Service]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;ExecStart&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;/opt/gitea/gitea web&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;WorkingDirectory&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;/opt/gitea&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;User&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;git&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;Type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;simple&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;[Install]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;WantedBy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;multi-user.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once this is saved, start the service.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;systemctl daemon-reload
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;systemctl start gitea
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Optionally, also configure it to start on boot.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;systemctl &lt;span class=&#34;nb&#34;&gt;enable&lt;/span&gt; gitea
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;jenkins-installation&#34;&gt;Jenkins installation
&lt;/h2&gt;&lt;p&gt;I installed Jenkins from the official Debian repo at &lt;code&gt;jenkins-ci.org&lt;/code&gt;, and clicked through the initial install.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-04.png&#34;
	width=&#34;2552&#34;
	height=&#34;618&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-04_hu_2463a9cba85f2b59.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-04_hu_ce6f7c06f30627f3.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;412&#34;
		data-flex-basis=&#34;991px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;add-plugin&#34;&gt;Add plugin
&lt;/h2&gt;&lt;p&gt;Open up &lt;strong&gt;Manage Jenkins&lt;/strong&gt; → &lt;strong&gt;Manage Plugins&lt;/strong&gt;. Navigate to &lt;strong&gt;Available&lt;/strong&gt; and check the &lt;strong&gt;Gitea&lt;/strong&gt; plugin.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2019-04-gitea-21.png&#34;
	width=&#34;1465&#34;
	height=&#34;110&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2019-04-gitea-21_hu_21b31ab36a23e5ed.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2019-04-gitea-21_hu_2f5b496dfbeba704.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;1331&#34;
		data-flex-basis=&#34;3196px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Next, install the plugin and restart Jenkins.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2019-04-gitea-22.png&#34;
	width=&#34;885&#34;
	height=&#34;183&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2019-04-gitea-22_hu_af9c0af27ee78fa7.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2019-04-gitea-22_hu_791bc460d76e3266.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;483&#34;
		data-flex-basis=&#34;1160px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The configuration for the plugin is located under &lt;strong&gt;Manage Jenkins&lt;/strong&gt; → &lt;strong&gt;Configure System&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-01.png&#34;
	width=&#34;1178&#34;
	height=&#34;180&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-01_hu_62ae3f96a9f87fe7.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-01_hu_10a935f07c5d23dc.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;654&#34;
		data-flex-basis=&#34;1570px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;At this point you will want to tell Jenkins where to find your Gitea server.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-02.png&#34;
	width=&#34;2604&#34;
	height=&#34;618&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-02_hu_912b5b7f30de2a28.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-02_hu_17c83376e68f87fa.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;421&#34;
		data-flex-basis=&#34;1011px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t suggest choosing &lt;strong&gt;Manage hooks&lt;/strong&gt;, because it uses the same account to manage hooks across all repos, which would violate the &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Principle_of_least_privilege&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;principle of least privilege&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;set-up-a-project-in-gitea&#34;&gt;Set up a project in Gitea
&lt;/h2&gt;&lt;p&gt;In Gitea, create a project, then a repository under that.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-03.png&#34;
	width=&#34;2552&#34;
	height=&#34;1578&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-03_hu_929d18d27e1e44e.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-03_hu_f2a90d7757207e08.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;161&#34;
		data-flex-basis=&#34;388px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Register an account in Gitea for Jenkins to use for this project.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-10.png&#34;
	width=&#34;2532&#34;
	height=&#34;960&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-10_hu_5bda42db1120735a.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-10_hu_4023d76d96db012e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;263&#34;
		data-flex-basis=&#34;633px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Log out, log back in as yourself, and add Jenkins as a collaborator to the repo, with &lt;strong&gt;Write&lt;/strong&gt; access.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-11.png&#34;
	width=&#34;2526&#34;
	height=&#34;848&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-11_hu_16246866460f82a1.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-11_hu_35375adabb3d4fdb.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;297&#34;
		data-flex-basis=&#34;714px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This is the only permission you need for public repositories. If you plan to lock down your Gitea organization later, then you will also need to give this Jenkins account &lt;strong&gt;Read&lt;/strong&gt; access at the organization level.&lt;/p&gt;
&lt;h2 id=&#34;set-up-a-project-in-jenkins&#34;&gt;Set up a project in Jenkins
&lt;/h2&gt;&lt;p&gt;Add a new &lt;strong&gt;Gitea Organization&lt;/strong&gt; Jenkins job.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-05.png&#34;
	width=&#34;1956&#34;
	height=&#34;160&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-05_hu_40c8a94460970dcd.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-05_hu_d6957b53cace1227.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;1222&#34;
		data-flex-basis=&#34;2934px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Enter the name of the organization, and the account to log in with.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-06.png&#34;
	width=&#34;1896&#34;
	height=&#34;1112&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-06_hu_d419d4a6c3badd9.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-06_hu_890fb6d035ec9347.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;170&#34;
		data-flex-basis=&#34;409px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Add the details for the new account, and make sure it&amp;rsquo;s selected.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-12.png&#34;
	width=&#34;1898&#34;
	height=&#34;998&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-12_hu_25ae18004c3026d9.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-12_hu_12be515ce76349a7.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;190&#34;
		data-flex-basis=&#34;456px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-13.png&#34;
	width=&#34;1896&#34;
	height=&#34;352&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-13_hu_3d2112f04a5d72bd.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-13_hu_426b00782d3ec20e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;538&#34;
		data-flex-basis=&#34;1292px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The other options don&amp;rsquo;t need to be changed at this stage.&lt;/p&gt;
&lt;p&gt;When you press &amp;lsquo;save&amp;rsquo;, Jenkins will immediately attempt to find any repositories in the Gitea organization, and kick off any builds. Unless everything is correct, this is unlikely to work the first time, so pay attention to error logs.&lt;/p&gt;
&lt;p&gt;These three places will show what&amp;rsquo;s happening:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Scan Gitea Organization Log&lt;/strong&gt;, which lists repositories in the organization.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scan Multibranch Pipeline Log&lt;/strong&gt; for each repository, which shows the discovery of branches.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Console output&lt;/strong&gt; for each build, which will show errors if the build status could not be submitted.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Problems which I&amp;rsquo;ve found here include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The URL of Gitea in the Jenkins configuration must match the URL to Gitea in its own configuration.&lt;/li&gt;
&lt;li&gt;The Jenkins user account must have permission to list repositories, clone, and update statuses.&lt;/li&gt;
&lt;li&gt;Empty repositories, and repositories without a &amp;lsquo;Jenkinsfile&amp;rsquo; are ignored.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For that last step, here is an empty &lt;code&gt;Jenkinsfile&lt;/code&gt; that you can put in your repository to test this integration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pipeline {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    agent any
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    stages {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        stage(&amp;#39;Do nothing&amp;#39;) {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            steps {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                sh &amp;#39;/bin/true&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once this is sorted out, you can expect to see your repository in Jenkins.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-07.png&#34;
	width=&#34;2546&#34;
	height=&#34;876&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-07_hu_4a50d12a111dbfa0.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-07_hu_78c656866d060adb.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;290&#34;
		data-flex-basis=&#34;697px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Every branch with a Jenkinsfile will appear.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-08.png&#34;
	width=&#34;2558&#34;
	height=&#34;886&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-08_hu_1f3be925699f9472.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-08_hu_7e65a4070725a542.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;288&#34;
		data-flex-basis=&#34;692px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;And each time a commit is mentioned in Gitea, it will display a small icon to indicate the build status.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-14.png&#34;
	width=&#34;2350&#34;
	height=&#34;706&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-14_hu_f141ae27a4e96660.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-14_hu_fba0f31cd5aea7c5.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;332&#34;
		data-flex-basis=&#34;798px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;set-up-a-web-hook-in-gitea&#34;&gt;Set up a web hook in Gitea
&lt;/h2&gt;&lt;p&gt;At this point, builds need to be manually triggered. To trigger them each time the repository changes, we need to get a notification out to Jenkins.&lt;/p&gt;
&lt;p&gt;Under the repository settings, click &lt;strong&gt;Webhooks&lt;/strong&gt; → &lt;strong&gt;Add webhook&lt;/strong&gt; → &lt;strong&gt;Gitea&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2019-04-gitea-22-1.png&#34;
	width=&#34;1521&#34;
	height=&#34;445&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2019-04-gitea-22-1_hu_f074dc259ff189fa.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2019-04-gitea-22-1_hu_4a26ad0b49a6980a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;341&#34;
		data-flex-basis=&#34;820px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The correct values to use are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;URL: &lt;code&gt;http://[ your jenkins server ]/gitea-webhook/post&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;POST Content Type: &lt;code&gt;application/json&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2019-04-gitea-23.png&#34;
	width=&#34;1356&#34;
	height=&#34;605&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2019-04-gitea-23_hu_f20ce6798dcfb520.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2019-04-gitea-23_hu_3569e4b730effefc.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;224&#34;
		data-flex-basis=&#34;537px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Once you press &lt;strong&gt;Add Webhook&lt;/strong&gt;, the path will appear with a small grey dot, indicating that it hasn&amp;rsquo;t been run before.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2019-04-gitea-24.png&#34;
	width=&#34;1284&#34;
	height=&#34;449&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2019-04-gitea-24_hu_beea68a2de47adf7.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2019-04-gitea-24_hu_8a95348c5c812631.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;285&#34;
		data-flex-basis=&#34;686px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;If you click edit, then the &lt;strong&gt;Test Delivery&lt;/strong&gt; button can be used to check that it&amp;rsquo;s working.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2019-04-gitea-25.png&#34;
	width=&#34;1209&#34;
	height=&#34;117&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2019-04-gitea-25_hu_7897eedb342fbe4c.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2019-04-gitea-25_hu_dc5680619f7c9fd7.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;1033&#34;
		data-flex-basis=&#34;2480px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The icon indicates the status. If things aren&amp;rsquo;t working correctly, then click the delivery UUID to expand the full request information, which should help with debugging.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2019-04-gitea-26.png&#34;
	width=&#34;1172&#34;
	height=&#34;131&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2019-04-gitea-26_hu_6af83469c1bfb466.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2019-04-gitea-26_hu_b032e1280b7b74ad.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;894&#34;
		data-flex-basis=&#34;2147px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;final-result&#34;&gt;Final result
&lt;/h2&gt;&lt;p&gt;With Jenkins and Gitea, you have a simple self-hosted a continuous integration environment.&lt;/p&gt;
&lt;p&gt;In Gitea, you can store, update and review your code. Any build and test steps in a &lt;code&gt;Jenkinsfile&lt;/code&gt; will be run automatically each time the repository changes.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-20.png&#34;
	width=&#34;2434&#34;
	height=&#34;1274&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-20_hu_c790e9427e83e6be.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-20_hu_e57e092c45e43831.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;191&#34;
		data-flex-basis=&#34;458px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The detailed output for each build is visible in Jenkins, where you can track build results with a variety of plugins.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-18.png&#34;
	width=&#34;3022&#34;
	height=&#34;1034&#34;
	srcset=&#34;https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-18_hu_6352f5c449e9c026.png 480w, https://mike42.me/blog/2019-05-how-to-integrate-gitea-and-jenkins/2018-04-gitea-18_hu_f2ad0e0c785dc203.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;292&#34;
		data-flex-basis=&#34;701px&#34;
	
&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Handling I/O errors in PHP</title>
        <link>https://mike42.me/blog/2019-03-handling-io-errors-in-php</link>
        <pubDate>Thu, 07 Mar 2019 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2019-03-handling-io-errors-in-php</guid>
        <description>&lt;p&gt;This blog post is all about how to handle errors from the PHP &lt;code&gt;file_get_contents&lt;/code&gt; function, and others which work like it.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;file_get_contents&lt;/code&gt; function will read the contents of a file into a &lt;code&gt;string&lt;/code&gt;. For example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;file_get_contents&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;hello.txt&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can try this out on the command-line like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt; &amp;gt; hello.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ php test.php
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;hello
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function is widely used, but I&amp;rsquo;ve observed that error handling around it is often not quite right. I&amp;rsquo;ve fixed a few bugs involving incorrect I/O error handling recently, so here are my thoughts on how it should be done.&lt;/p&gt;
&lt;h2 id=&#34;how-file_get_contents-fails&#34;&gt;How file_get_contents fails
&lt;/h2&gt;&lt;p&gt;For legacy reasons, this function does not throw an exception when something goes wrong. Instead, it will both log a warning, and return &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$filename&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;not-a-real-file.txt&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;file_get_contents&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Which looks like this when you run it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ php test.php
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PHP Warning:  file_get_contents&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;not-a-real-file.txt&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: failed to open stream: No such file or directory in test.php on line &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PHP Stack trace:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PHP   1. &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;main&lt;span class=&#34;o&#34;&gt;}()&lt;/span&gt; test.php:0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PHP   2. file_get_contents&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; test.php:3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Warnings are not very useful on their own, because the code will continue on without the correct data.&lt;/p&gt;
&lt;h2 id=&#34;error-handling-in-four-steps&#34;&gt;Error handling in four steps
&lt;/h2&gt;&lt;p&gt;If anything goes wrong when you are reading a file, your code should be throwing some type of &lt;code&gt;Exception&lt;/code&gt; which describes the problem. This allows developers to put a &lt;code&gt;try {} catch {}&lt;/code&gt; around it, and avoids nasty surprises where invalid data is used later.&lt;/p&gt;
&lt;h3 id=&#34;step-1-detect-that-the-file-was-not-read&#34;&gt;Step 1: Detect that the file was not read
&lt;/h3&gt;&lt;p&gt;Any call to &lt;code&gt;file_get_contents&lt;/code&gt; should be immediately followed by a check for that &lt;code&gt;false&lt;/code&gt; return value. This is how you know that there is a problem.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$filename&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;not-a-real-file.txt&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;file_get_contents&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;throw&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Exception&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;File was not loaded&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This now gives both a warning and an uncaught exception:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ php test.php
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PHP Warning:  file_get_contents&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;not-a-real-file.txt&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: failed to open stream: No such file or directory in test.php on line &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PHP Stack trace:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PHP   1. &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;main&lt;span class=&#34;o&#34;&gt;}()&lt;/span&gt; test.php:0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PHP   2. file_get_contents&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; test.php:3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PHP Fatal error:  Uncaught Exception: File was not loaded in test.php:5
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Stack trace:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#0 {main}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  thrown in test.php on line &lt;span class=&#34;m&#34;&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;step-2-suppress-the-warning&#34;&gt;Step 2: Suppress the warning
&lt;/h3&gt;&lt;p&gt;Warnings are usually harmless, but there are several good reasons to suppress them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It ensures that you are not depending on a global error handler (or the absence of one) for correct behaviour.&lt;/li&gt;
&lt;li&gt;The warning might appear in the middle of the output, depending on &lt;code&gt;php.ini&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Warnings can produce a lot of noise in the logs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Use &lt;code&gt;@&lt;/code&gt; to silence any warnings from a function call.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$filename&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;not-a-real-file.txt&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;file_get_contents&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;throw&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Exception&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;File was not loaded&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The output is now only the uncaught &lt;code&gt;Exception&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ php test.php
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PHP Fatal error:  Uncaught Exception: File was not loaded in test.php:5
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Stack trace:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#0 {main}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  thrown in test.php on line &lt;span class=&#34;m&#34;&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;step-3-get-the-reason-for-the-failure&#34;&gt;Step 3: Get the reason for the failure
&lt;/h3&gt;&lt;p&gt;Unfortunately, we lost the &amp;ldquo;No such file or directory&amp;rdquo; message, which is pretty important information, which should go in the &lt;code&gt;Exception&lt;/code&gt;. This information is retrieved from the old-style &lt;code&gt;error_get_last&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;This function might just return empty data, so you should check that everything is set and non-empty before you try to use it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$filename&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;not-a-real-file.txt&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;error_clear_last&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;file_get_contents&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;error_get_last&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nv&#34;&gt;$error&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;isset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;isset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;message&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;message&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;message&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Check that the file exists and can be read.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;throw&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Exception&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;File &amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$filename&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#39; was not loaded. &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$error&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This now embeds the failure reason directly in the message.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;php&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;PHP&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Fatal&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;Uncaught&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Exception&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;ne&#34;&gt;File&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;not-a-real-file.txt&amp;#39;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;was&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;loaded&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file_get_contents&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;real&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;txt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;failed&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;open&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;stream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;No&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;such&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;directory&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;php&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Stack&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;trace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#0 {main}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;thrown&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;php&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;step-4-add-a-fallback&#34;&gt;Step 4: Add a fallback
&lt;/h3&gt;&lt;p&gt;The last time I introduced &lt;code&gt;error_clear_last()&lt;/code&gt;/&lt;code&gt;get_last_error()&lt;/code&gt; into a code-base, I learned that HHVM does not have these functions.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Call to undefined function error_clear_last()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The fix for this is to write &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/gfx-php/pull/37/commits/d2b2cd21ab13727d2dbda6a42f151d8443045d47&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;some wrapper code&lt;/a&gt;, to verify that each function exists.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$filename&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;not-a-real-file&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;clearLastError&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;file_get_contents&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$error&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;getLastErrorOrDefault&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Check that the file exists and can be read.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;throw&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;\Exception&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Could not retrieve image data from &amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$filename&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#39;. &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$error&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * Call error_clear_last() if it exists. This is dependent on which PHP runtime is used.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;clearLastError&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;function_exists&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;error_clear_last&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;error_clear_last&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * Retrieve the message from error_get_last() if possible. This is very useful for debugging, but it will not
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * always exist or return anything useful.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;getLastErrorOrDefault&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$default&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;function_exists&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;error_clear_last&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;error_get_last&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;isset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;isset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;message&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;message&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;message&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$default&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This does the same thing as before, but without breaking other PHP runtimes.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ php test.php
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PHP Fatal error:  Uncaught Exception: Could not retrieve image data from &amp;#39;not-a-real-file&amp;#39;. file_get_contents(not-a-real-file): failed to open stream: No such file or directory in test.php:7
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Stack trace:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#0 {main}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  thrown in test.php on line 7
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since HHVM is dropping support for PHP, I expect that this last step will soon become unnecessary.&lt;/p&gt;
&lt;h2 id=&#34;how-not-to-handle-errors&#34;&gt;How not to handle errors
&lt;/h2&gt;&lt;p&gt;Some applications put a series of checks before each I/O operation, and then simply perform the operation with no error handling. An example of this would be:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$filename&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;not-a-real-file.txt&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Check everything!
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;file_exists&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;throw&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Exception&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$filename&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; does not exist&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;is_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;throw&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Exception&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$filename&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; is not a file&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;is_readable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;throw&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Exception&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$filename&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; cannot be read&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Assume that nothing can possibly go wrong..
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;file_get_contents&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You could probably make a reasonable-sounding argument that pre-emptive checks are a good idea, but I consider them to be misguided:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you skip any actual error handling, then your code is going to fail in more surprising ways when you encounter an I/O problem that could not be detected.&lt;/li&gt;
&lt;li&gt;If you do perform correct error handling as well, then the extra checks add nothing other than more branches to test.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lastly, beware of false positives. For example, the above snippet will reject HTTP URL&amp;rsquo;s, which are perfectly valid for &lt;code&gt;file_get_contents&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;Most PHP code now uses &lt;code&gt;try&lt;/code&gt;/&lt;code&gt;catch&lt;/code&gt;/&lt;code&gt;finally&lt;/code&gt; blocks to handle problems, but the ecosystem really values backwards compatibility, so existing functions are rarely changed.&lt;/p&gt;
&lt;p&gt;The style of error reporting used in these I/O functions is by now a legacy quirk, and should be wrapped to consistently throw a useful &lt;code&gt;Exception&lt;/code&gt;.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>The top 100 Ansible modules</title>
        <link>https://mike42.me/blog/2019-01-the-top-100-ansible-modules</link>
        <pubDate>Wed, 30 Jan 2019 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2019-01-the-top-100-ansible-modules</guid>
        <description>&lt;p&gt;Ansible is an automation system which is widely used for deployments and configuration. It contains a dizzying array of modules for interfacing with things like files, services, package managers, and various pieces of software and hardware.&lt;/p&gt;
&lt;h2 id=&#34;background&#34;&gt;Background
&lt;/h2&gt;&lt;p&gt;There are some modules which I would expect every Ansible user to be familiar with, while others are barely used at all. I could have a guess about which modules I use most, but what about the wider community?&lt;/p&gt;
&lt;p&gt;I couldn&amp;rsquo;t find any existing data, so I set out to determine which Ansible modules were most widely-used. The best source for this is Ansible Galaxy, which is a directory of around 18,000 Ansible roles. Using some scripts, I sifted through the 18,259 publicly accessible roles from Ansible Galaxy, found 71,610 files to look through, and tallied up which modules were being used by each of the 317,757 tasks in those files.&lt;/p&gt;
&lt;h2 id=&#34;the-list&#34;&gt;The list
&lt;/h2&gt;&lt;p&gt;These are the top 100 modules as of January 2019. I used the same method to build such a list in January 2018, so you can also see the change in popularity of some modules over the last 12 months.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Rank&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Module&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Uses&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Rank +/-&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;1&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/file_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;file&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;26,224&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+1&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;2&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/include_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;include&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;25,267&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-1&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;3&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/template_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;template&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;24,062&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;4&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/command_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;command&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;23,952&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;5&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/service_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;service&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;19,436&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;6&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/shell_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;shell&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;19,401&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;7&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/set_fact_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;set_fact&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;17,079&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+1&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;8&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/apt_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;apt&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;16,006&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+1&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;9&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/lineinfile_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;lineinfile&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;12,432&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-2&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;10&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/copy_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;copy&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;8,794&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+1&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;11&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/yum_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;yum&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;8,733&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-1&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;12&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/assert_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;assert&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;7,504&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+7&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;13&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/include_tasks_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;include_tasks&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;6,686&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+15&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;14&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/stat_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;stat&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;5,922&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-2&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;15&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/package_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;package&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;5,422&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-1&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;16&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/get_url_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;get_url&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;5,323&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-3&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;17&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/debug_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;debug&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;5,147&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-2&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;18&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/import_tasks_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;import_tasks&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;5,016&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+20&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;19&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/include_vars_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;include_vars&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;4,251&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-2&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;20&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/apt_repository_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;apt_repository&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;3,789&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-4&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;21&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/user_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;user&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;3,233&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-3&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;22&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/fail_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;fail&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;2,812&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+2&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;23&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/unarchive_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;unarchive&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;2,734&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-2&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;24&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/apt_key_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;apt_key&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;2,665&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-4&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;25&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/pip_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;pip&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;2,474&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;26&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/systemd_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;systemd&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;2,389&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+8&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;27&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/user_guide/playbooks_delegation.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;action&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;2,114&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-4&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;28&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/git_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;git&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;2,043&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-1&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;29&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/uri_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;uri&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;1,680&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+7&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;30&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/group_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;group&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;1,665&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-1&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;31&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/sysctl_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;sysctl&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;1,331&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-5&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;32&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/raw_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;raw&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;1,323&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-2&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;33&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/mysql_user_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mysql_user&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;1,266&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;34&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/meta_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;meta&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;1,204&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+3&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;35&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/replace_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;replace&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;1,125&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-3&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;36&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/ini_file_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;ini_file&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;1,125&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-5&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;37&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/find_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;find&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;1,030&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-15&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;38&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/local_action_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;local_action&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;986&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-3&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;39&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/mysql_db_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mysql_db&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;959&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;40&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/cron_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;cron&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;925&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;41&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/wait_for_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;wait_for&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;898&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;42&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/rpm_key_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;rpm_key&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;771&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;43&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/include_role_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;include_role&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;742&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+15&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;44&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/yum_repository_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;yum_repository&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;723&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+2&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;45&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/mount_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mount&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;669&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-2&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;46&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/blockinfile_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;blockinfile&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;619&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+3&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;47&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/firewalld_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;firewalld&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;579&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+1&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;48&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/ufw_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;ufw&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;563&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-1&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;49&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/authorized_key_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;authorized_key&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;557&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-4&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;50&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/docker_container_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;docker_container&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;488&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+2&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;51&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/dnf_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;dnf&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;455&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+5&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;52&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/seboolean_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;seboolean&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;417&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-8&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;53&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/homebrew_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;homebrew&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;409&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-2&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;54&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/fetch_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;fetch&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;378&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+1&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;55&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/npm_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;npm&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;367&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-5&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;56&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/osx_defaults_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;osx_defaults&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;363&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+8&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;57&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/postgresql_user_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;postgresql_user&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;350&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-4&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;58&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/pkgng_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;pkgng&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;345&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-4&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;59&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/pause_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;pause&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;340&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+4&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;60&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/script_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;script&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;314&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+5&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;61&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/setup_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;setup&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;290&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+7&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;62&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/postgresql_db_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;postgresql_db&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;289&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-2&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;63&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/mysql_replication_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mysql_replication&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;286&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-1&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;64&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/win_regedit_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;win_regedit&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;281&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+6&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;65&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/pacman_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;pacman&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;257&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-4&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;66&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/debconf_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;debconf&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;256&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+1&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;67&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/slurp_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;slurp&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;255&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+10&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;68&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/gem_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;gem&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;253&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-11&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;69&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/iptables_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;iptables&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;240&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+13&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;70&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/apache2_module_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;apache2_module&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;231&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-4&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;71&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/synchronize_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;synchronize&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;213&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-2&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;72&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/2.6/modules/docker_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;docker&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;213&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-13&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;73&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/alternatives_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;alternatives&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;210&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;74&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/selinux_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;selinux&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;202&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;75&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/openshift/openshift-ansible&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;oc_obj&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;199&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+98&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;76&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/make_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;make&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;194&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-1&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;77&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/win_shell_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;win_shell&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;191&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+13&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;78&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/modprobe_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;modprobe&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;187&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+11&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;79&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/hostname_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;hostname&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;181&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-7&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;80&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/zypper_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;zypper&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;174&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-4&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;81&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/xml_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;xml&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;160&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;82&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/supervisorctl_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;supervisorctl&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;160&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-11&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;83&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/win_file_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;win_file&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;149&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+15&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;84&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/homebrew_cask_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;homebrew_cask&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;149&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-6&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;85&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/add_host_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;add_host&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;144&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-2&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;86&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/rabbitmq_user_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;rabbitmq_user&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;129&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-7&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;87&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/pamd_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;pamd&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;124&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+81&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;88&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/win_command_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;win_command&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;116&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+13&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;89&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/assemble_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;assemble&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;116&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-9&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;90&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/htpasswd_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;htpasswd&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;115&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-6&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;91&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/apk_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;apk&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;112&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-5&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;92&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/openbsd_pkg_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;openbsd_pkg&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;111&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-7&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;93&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/win_get_url_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;win_get_url&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;109&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+14&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;94&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/win_chocolatey_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;win_chocolatey&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;109&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;95&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/docker_image_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;docker_image&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;109&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+4&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;96&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/tempfile_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;tempfile&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;106&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;+25&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;97&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/locale_gen_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;locale_gen&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;105&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-5&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;98&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/easy_install_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;easy_install&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;97&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-10&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;99&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/django_manage_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;django_manage&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;97&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-3&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;100&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.ansible.com/ansible/latest/modules/composer_module.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;composer&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;96&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;-3&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Out of over 2,500 modules mentioned in Ansible Galaxy, it turns out that only a few dozen are widely used. Following this, there is a long tail of infrequently-used and custom modules.&lt;/p&gt;
&lt;h2 id=&#34;how-many-modules-do-i-need-to-know&#34;&gt;How many modules do I need to know?
&lt;/h2&gt;&lt;p&gt;You can write 80% of the roles in Ansible Galaxy using only the 74 most popular Ansible modules.&lt;/p&gt;
&lt;p&gt;For writing an individual Ansible role, you don&amp;rsquo;t need anywhere near this many. The median number of modules used by an role in Ansible Galaxy is just 6.&lt;/p&gt;
&lt;p&gt;There are a few reasons that you won&amp;rsquo;t need to use many popular modules all at the same time:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Different technologies: eg. &lt;code&gt;mysql_db&lt;/code&gt; and &lt;code&gt;postgresql_db&lt;/code&gt; set up different databases, and would be invoked by different roles if you need both.&lt;/li&gt;
&lt;li&gt;Obsolete modules: eg. &lt;code&gt;docker&lt;/code&gt; has been split up, and new code will use &lt;code&gt;docker_container&lt;/code&gt; instead.&lt;/li&gt;
&lt;li&gt;Different levels of abstraction: eg. cross-platform developers will use the &lt;code&gt;package&lt;/code&gt; module, while developers who know their platform may directly use the &lt;code&gt;apt&lt;/code&gt;, &lt;code&gt;dnf&lt;/code&gt; and &lt;code&gt;yum&lt;/code&gt; modules. You are unlikely to see these mixed.&lt;/li&gt;
&lt;li&gt;Different styles: &lt;code&gt;include_tasks&lt;/code&gt; vs. &lt;code&gt;import_tasks&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;some-notes&#34;&gt;Some notes
&lt;/h2&gt;&lt;p&gt;Here are some things to keep in mind when reading the table.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I skipped any role that was not hosted in a public GitHub repository, or could not be parsed. A &lt;a class=&#34;link&#34; href=&#34;https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=920569&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;php-yaml bug&lt;/a&gt; also kept a few files out of the 2019 tally.&lt;/li&gt;
&lt;li&gt;Each task was counted only once, so &lt;code&gt;local_action&lt;/code&gt; and &lt;code&gt;action&lt;/code&gt; are obscuring which modules were eventually executed.&lt;/li&gt;
&lt;li&gt;The OpenShift &lt;code&gt;oc_obj&lt;/code&gt; module on this list is not bundled with Ansible (the module itself is distributed through Galaxy).&lt;/li&gt;
&lt;li&gt;I did not attempt to exclude abandoned or incomplete packages. Eg. The &lt;code&gt;docker&lt;/code&gt; module on this list has been removed from the latest version, but remains popular in existing Ansible Galaxy roles.&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>Thermal Sans Mono: A new bitmap font for receipt printers</title>
        <link>https://mike42.me/blog/2018-10-thermal-sans-mono-font</link>
        <pubDate>Thu, 01 Nov 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-10-thermal-sans-mono-font</guid>
        <description>&lt;p&gt;Today I&amp;rsquo;m writing about a new project that I&amp;rsquo;ve started to create a font, called &amp;ldquo;Thermal Sans Mono&amp;rdquo;. I&amp;rsquo;m hoping to make this into a set of specialized free bitmap fonts for use on thermal receipt printers and printer emulators.&lt;/p&gt;
&lt;p&gt;Here is what it looks like so far:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-10-thermal-sans-mono-font/2018-06-thermal-sans-mono.png&#34;
	width=&#34;312&#34;
	height=&#34;96&#34;
	srcset=&#34;https://mike42.me/blog/2018-10-thermal-sans-mono-font/2018-06-thermal-sans-mono_hu_ebe675981b2e6c1.png 480w, https://mike42.me/blog/2018-10-thermal-sans-mono-font/2018-06-thermal-sans-mono_hu_1b28b13579ee1d07.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;325&#34;
		data-flex-basis=&#34;780px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;In this blog post I&amp;rsquo;ll talk a bit about why I needed a new font, how it&amp;rsquo;s derived from GNU Unifont, and what I&amp;rsquo;m planning to do with it.&lt;/p&gt;
&lt;h2 id=&#34;background&#34;&gt;Background
&lt;/h2&gt;&lt;p&gt;Firstly, I am solving a technical problem, not a design problem.&lt;/p&gt;
&lt;p&gt;Printing non-ASCII characters on receipts can get a bit complex, especially if you have a lot of different printers to support. Each thermal receipt printer has a different set of available &amp;ldquo;code pages&amp;rdquo; of glyphs, which makes localisation a real adventure.&lt;/p&gt;
&lt;p&gt;Using the &lt;a class=&#34;link&#34; href=&#34;https://github.com/receipt-print-hq/escpos-printer-db&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;escpos-printer-db&lt;/a&gt; project, we can currently create software which accepts UTF-8 text, then switches between the available code pages to render text for a specific printer. I&amp;rsquo;m now looking at how we can encode characters that are &lt;em&gt;not&lt;/em&gt; in any available code page.&lt;/p&gt;
&lt;p&gt;For example, &lt;a class=&#34;link&#34; href=&#34;https://github.com/python-escpos/python-escpos/blob/fe08fc1469c1e27c3466c7671cfdbabaf9440486/src/escpos/magicencode.py#L263&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;in this code&lt;/a&gt; from the &lt;code&gt;python-escpos&lt;/code&gt; library, the &lt;code&gt;?&lt;/code&gt; substitution character still has to be printed for some characters:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;encoding&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;encoder&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find_suitable_encoding&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;encoding&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_handle_character_failed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Rather than send a &lt;code&gt;?&lt;/code&gt; character, I think we could retrieve a glyph from a suitable font and send it as a bitmap instead. I previously &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2018-03-using-custom-fonts-to-add-new-glyphs-to-an-epson-printer&#34; &gt;wrote about a technique&lt;/a&gt; to cache glyphs from GNU Unifont in printer memory, but these glyphs don&amp;rsquo;t have the correct size or weight to be displayed alongside the glyphs that the printer has rendered itself.&lt;/p&gt;
&lt;p&gt;Of course we can&amp;rsquo;t do this yet, because there is no suitable bitmap font.&lt;/p&gt;
&lt;h2 id=&#34;how-its-made&#34;&gt;How it&amp;rsquo;s made
&lt;/h2&gt;&lt;p&gt;The closest font to what we need is GNU Unifont, which is thankfully freely licensed. A Unifont glyph is typically 8x16 with a thin line and a lot of whitespace. I need to print in 12x24, with thick lines and no whitespace.&lt;/p&gt;
&lt;p&gt;To control as many variables as possible, I decided to pre-render a transformed version of GNU Unifont. This involved tracing the original glyph and re-drawing it with new parameters.&lt;/p&gt;
&lt;p&gt;The first step is to use a purpose-built algorithm to trace the lines from the glyph:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-10-thermal-sans-mono-font/0041-orig-enlarged.png&#34;
	width=&#34;80&#34;
	height=&#34;160&#34;
	srcset=&#34;https://mike42.me/blog/2018-10-thermal-sans-mono-font/0041-orig-enlarged_hu_a79f1736efafaadb.png 480w, https://mike42.me/blog/2018-10-thermal-sans-mono-font/0041-orig-enlarged_hu_d72e41d208e83f8e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;50&#34;
		data-flex-basis=&#34;120px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2018-10-thermal-sans-mono-font/0041-orig-traced.png&#34;
	width=&#34;80&#34;
	height=&#34;160&#34;
	srcset=&#34;https://mike42.me/blog/2018-10-thermal-sans-mono-font/0041-orig-traced_hu_2f1d9dfa614d68d8.png 480w, https://mike42.me/blog/2018-10-thermal-sans-mono-font/0041-orig-traced_hu_9814a4fd72762546.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;50&#34;
		data-flex-basis=&#34;120px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The points are then re-drawn onto a new canvas with a thicker outline, and a lot less whitespace.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-10-thermal-sans-mono-font/0041-large-points.png&#34;
	width=&#34;120&#34;
	height=&#34;240&#34;
	srcset=&#34;https://mike42.me/blog/2018-10-thermal-sans-mono-font/0041-large-points_hu_e48c769196b5bd17.png 480w, https://mike42.me/blog/2018-10-thermal-sans-mono-font/0041-large-points_hu_5385a488c6a98cd8.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;50&#34;
		data-flex-basis=&#34;120px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2018-10-thermal-sans-mono-font/0041-large.png&#34;
	width=&#34;120&#34;
	height=&#34;240&#34;
	srcset=&#34;https://mike42.me/blog/2018-10-thermal-sans-mono-font/0041-large_hu_575c16cd9f99bfa2.png 480w, https://mike42.me/blog/2018-10-thermal-sans-mono-font/0041-large_hu_820173641349e86e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;50&#34;
		data-flex-basis=&#34;120px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;When this canvas is scaled back to 12x24, we have our glyph.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-10-thermal-sans-mono-font/0041-scaled.png&#34;
	width=&#34;120&#34;
	height=&#34;240&#34;
	srcset=&#34;https://mike42.me/blog/2018-10-thermal-sans-mono-font/0041-scaled_hu_af04a05133b6684d.png 480w, https://mike42.me/blog/2018-10-thermal-sans-mono-font/0041-scaled_hu_14364daad84012fb.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;50&#34;
		data-flex-basis=&#34;120px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This glyph is now the correct size and weight for use on most thermal receipt printers.&lt;/p&gt;
&lt;h2 id=&#34;roadmap&#34;&gt;Roadmap
&lt;/h2&gt;&lt;p&gt;Currently, I have only processed the ASCII characters. As a GNU Unifont derivative, we should (with some effort) be able to include many more glyphs in the future.&lt;/p&gt;
&lt;p&gt;As a starting goal, I am aiming to make the font complete enough to include as a fallback font in the &lt;code&gt;escpos-php&lt;/code&gt; printing library.&lt;/p&gt;
&lt;h2 id=&#34;download&#34;&gt;Download
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;ve made my initial work on &amp;ldquo;Thermal Sans Mono&amp;rdquo; available on GitHub at &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/thermal-sans-mono&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/thermal-sans-mono&lt;/a&gt;. You can find it as a bitmap font in PCF and BDF format under the &amp;ldquo;Releases&amp;rdquo; section of the GitHub project.&lt;/p&gt;
&lt;p&gt;As always, bugs, comments and suggestions are appreciated.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Three ways to archive a website</title>
        <link>https://mike42.me/blog/2018-09-three-ways-to-archive-a-website</link>
        <pubDate>Thu, 13 Sep 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-09-three-ways-to-archive-a-website</guid>
        <description>&lt;p&gt;I recently needed to archive a small website before decommissioning it. There are a few distinct reasons you might want an archive of a website:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To archive the information in case you need it later.&lt;/li&gt;
&lt;li&gt;To archive the look and feel so that you can see how it has progressed.&lt;/li&gt;
&lt;li&gt;To archive the digital artifacts so that you can host them elsewhere as a mirror.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each of these produces files in a different format, which are useful over different time-periods. In this post, I&amp;rsquo;ll write a bit about all three, since it&amp;rsquo;s easiest to archive a website while it is still online.&lt;/p&gt;
&lt;h2 id=&#34;saving-webpage-content-to-pdf&#34;&gt;Saving webpage content to PDF
&lt;/h2&gt;&lt;p&gt;To write an individual page to a PDF, you can use &lt;code&gt;wkhtmltopdf&lt;/code&gt;. On Debian/Ubuntu, this can be installed with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install wkhtmltopdf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The only extra setting I use for this is the &amp;ldquo;Javascript delay&amp;rdquo;, since some parts of the page will be loaded after the main content.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir -p pdf/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wkhtmltopdf --javascript-delay 1000 https://example.com/ pdf/index.pdf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This produces &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2018-09-three-ways-to-archive-a-website/2018-09-index-1.pdf&#34; &gt;a PDF file&lt;/a&gt;, which you can copy/paste text from, or print.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-09-three-ways-to-archive-a-website/2018-09-index.png&#34;
	width=&#34;1013&#34;
	height=&#34;584&#34;
	srcset=&#34;https://mike42.me/blog/2018-09-three-ways-to-archive-a-website/2018-09-index_hu_5731d965b4ffe70e.png 480w, https://mike42.me/blog/2018-09-three-ways-to-archive-a-website/2018-09-index_hu_c6579d7fab0f119f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;173&#34;
		data-flex-basis=&#34;416px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;You then simply repeat this for every page which you want to archive.&lt;/p&gt;
&lt;h2 id=&#34;saving-webpage-content-to-an-image&#34;&gt;Saving webpage content to an image
&lt;/h2&gt;&lt;p&gt;If you are more interested in how the website looked, rather than what it contained, then you can use the same package to write it to an image. I use the &lt;code&gt;jpg&lt;/code&gt; format here, because the file sizes are reasonable at higher resolution. I also zoom the page 200% to get higher quality, and selected sizes which are typical of desktop, tablet and mobile screen sizes.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir -p jpg/desktop jpg/mobile jpg/tablet
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wkhtmltoimage --zoom 2.0 --javascript-delay 1000 --width 4380 https://example.com/ jpg/desktop/index.jpg
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wkhtmltoimage --zoom 2.0 --javascript-delay 1000 --width 2048 https://example.com/ jpg/tablet/index.jpg
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wkhtmltoimage --zoom 2.0 --javascript-delay 1000 --width 960 https://example.com/ jpg/mobile/index.jpg
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This gives you three images for the page. This example page is quite short, but a larger page produces a very tall image.&lt;/p&gt;
&lt;p&gt;The mobile and tablet versions are narrower.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-09-three-ways-to-archive-a-website/2018-09-index-mobile.jpg&#34;
	width=&#34;960&#34;
	height=&#34;436&#34;
	srcset=&#34;https://mike42.me/blog/2018-09-three-ways-to-archive-a-website/2018-09-index-mobile_hu_5f3cdfa4ab76f47a.jpg 480w, https://mike42.me/blog/2018-09-three-ways-to-archive-a-website/2018-09-index-mobile_hu_4543d5b6686f1409.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;220&#34;
		data-flex-basis=&#34;528px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2018-09-three-ways-to-archive-a-website/2018-09-index-tablet.jpg&#34;
	width=&#34;2048&#34;
	height=&#34;855&#34;
	srcset=&#34;https://mike42.me/blog/2018-09-three-ways-to-archive-a-website/2018-09-index-tablet_hu_7d70ae22a15125e.jpg 480w, https://mike42.me/blog/2018-09-three-ways-to-archive-a-website/2018-09-index-tablet_hu_c6d29ee7153725c7.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;239&#34;
		data-flex-basis=&#34;574px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;While the desktop version is full-width.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-09-three-ways-to-archive-a-website/2018-09-index-desktop.jpg&#34;
	width=&#34;4380&#34;
	height=&#34;855&#34;
	srcset=&#34;https://mike42.me/blog/2018-09-three-ways-to-archive-a-website/2018-09-index-desktop_hu_b3e5aed0d01e635f.jpg 480w, https://mike42.me/blog/2018-09-three-ways-to-archive-a-website/2018-09-index-desktop_hu_a88f633ec194790e.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;512&#34;
		data-flex-basis=&#34;1229px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;As above, this needs to be repeated for each page which you want to archive.&lt;/p&gt;
&lt;h2 id=&#34;mirroring-the-entire-site-as-html&#34;&gt;Mirroring the entire site as HTML
&lt;/h2&gt;&lt;p&gt;A full mirror of the site is a good short-term archive. Some websites have a lot of embedded external content like maps and external social media widgets, which I would expect to gradually stop working over time as these services change. Still, you might still be able to browse the website on your local computer in 10 or 20 years time, depending on how browsers change.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;wget&lt;/code&gt; is the go-to tool for mirroring sites, but it has a lot of options!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir -p html/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cd html
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wget \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --trust-server-names \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  -e robots=off \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --mirror \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --convert-links \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --adjust-extension \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --page-requisites \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --no-parent \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  https://example.com
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are quite a few options here, I&amp;rsquo;ll briefly explain why I used each one:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Option&lt;/th&gt;
          &lt;th&gt;Purpose&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;--trust-server-names&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;Allow the correct filename to be used when a redirect is used.&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;-e robots=off&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;Disable rate limiting. This is OK to use if you own the site and are sure that mirroring it will not cause capacity issues.&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;--mirror&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;Short-hand for some options to recursively download the site.&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;--convert-links&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;Change links on the target site to local ones.&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;--adjust-extension&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;If you get a page called &amp;ldquo;foo&amp;rdquo;, save it as &amp;ldquo;foo.html&amp;rdquo;.&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;--page-requisites&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;Also download CSS and Javascript files referenced on the page&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;--no-parent&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;Only download sub-pages from the starting page. This is useful if you want to fetch only part of the domain.&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The result can be opened locally in a web browser:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-09-three-ways-to-archive-a-website/2018-09-index-html.png&#34;
	width=&#34;1484&#34;
	height=&#34;784&#34;
	srcset=&#34;https://mike42.me/blog/2018-09-three-ways-to-archive-a-website/2018-09-index-html_hu_f9cf77b9b39ed49b.png 480w, https://mike42.me/blog/2018-09-three-ways-to-archive-a-website/2018-09-index-html_hu_88f08d4928c43215.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;189&#34;
		data-flex-basis=&#34;454px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;These options worked well for me on a Wordpress site.&lt;/p&gt;
&lt;h2 id=&#34;putting-it-all-together&#34;&gt;Putting it all together
&lt;/h2&gt;&lt;p&gt;The site I was mirroring was quite small, so I manually assembled a list of pages to mirror, gave each a name, and wrote them in a text file called &lt;code&gt;urls.txt&lt;/code&gt; in this format:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;https://site.example/ index
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;https://site.example/foo foo
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;https://site.example/bar bar
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I then ran this script to mirror each URL as an image and PDF, before mirroring the entire site locally in HTML.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -exu -o pipefail
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir -p jpg/desktop jpg/mobile jpg/tablet html/ pdf
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;read&lt;/span&gt; page_url page_name&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;## &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$page_url&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; (&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$page_name&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;# JPEG archive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  wkhtmltoimage --zoom 2.0 --javascript-delay &lt;span class=&#34;m&#34;&gt;1000&lt;/span&gt; --width &lt;span class=&#34;m&#34;&gt;4380&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$page_url&lt;/span&gt; jpg/desktop/&lt;span class=&#34;nv&#34;&gt;$page_name&lt;/span&gt;.jpg
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  wkhtmltoimage --zoom 2.0 --javascript-delay &lt;span class=&#34;m&#34;&gt;1000&lt;/span&gt; --width &lt;span class=&#34;m&#34;&gt;2048&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$page_url&lt;/span&gt; jpg/tablet/&lt;span class=&#34;nv&#34;&gt;$page_name&lt;/span&gt;.jpg
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  wkhtmltoimage --zoom 2.0 --javascript-delay &lt;span class=&#34;m&#34;&gt;1000&lt;/span&gt; --width &lt;span class=&#34;m&#34;&gt;960&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$page_url&lt;/span&gt; jpg/mobile/&lt;span class=&#34;nv&#34;&gt;$page_name&lt;/span&gt;.jpg
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;# Printable archive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  wkhtmltopdf --javascript-delay &lt;span class=&#34;m&#34;&gt;1000&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$page_url&lt;/span&gt; pdf/&lt;span class=&#34;nv&#34;&gt;$page_name&lt;/span&gt;.pdf
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;done&lt;/span&gt; &amp;lt; urls.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Browsable archive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;MAIN_PAGE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;head -n1 urls.txt &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; cut -d&lt;span class=&#34;s1&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt; -f1&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir -p html/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; html &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  wget --trust-server-names -e &lt;span class=&#34;nv&#34;&gt;robots&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;off --mirror --convert-links --adjust-extension --page-requisites --no-parent &lt;span class=&#34;nv&#34;&gt;$MAIN_PAGE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;example.com&lt;/code&gt; domain only has an index page, so after running the script against it, it downloads this set of files:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── archive.sh
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── html
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   └── example.com
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│       └── index.html
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── jpg
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── desktop
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   │   └── index.jpg
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── mobile
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   │   └── index.jpg
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   └── tablet
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│       └── index.jpg
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── pdf
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   └── index.pdf
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;└── urls.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Happy archiving!&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Monitoring network throughput with Prometheus</title>
        <link>https://mike42.me/blog/2018-08-monitoring-network-throughput</link>
        <pubDate>Thu, 23 Aug 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-08-monitoring-network-throughput</guid>
        <description>&lt;p&gt;Today I&amp;rsquo;m writing a bit about a Prometheus deployment that I made last year on a Raspberry Pi, to get better data about congestion on my uplink to the Internet.&lt;/p&gt;
&lt;h2 id=&#34;the-problem&#34;&gt;The problem
&lt;/h2&gt;&lt;p&gt;You have probably run an Internet speed test before, like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-08-monitoring-network-throughput/2017-07-net-05.png&#34;
	width=&#34;2382&#34;
	height=&#34;1050&#34;
	srcset=&#34;https://mike42.me/blog/2018-08-monitoring-network-throughput/2017-07-net-05_hu_25e03560aaaa0e7a.png 480w, https://mike42.me/blog/2018-08-monitoring-network-throughput/2017-07-net-05_hu_25e78b5d6b5f612f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;226&#34;
		data-flex-basis=&#34;544px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;A speed test will tell you how slow your computer&amp;rsquo;s connection is, but it can&amp;rsquo;t narrow down whether it&amp;rsquo;s because of other LAN devices, the line quality, or congestion at the provider.&lt;/p&gt;
&lt;p&gt;You can start to assemble this information from the router, which has counters for each network interface.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-08-monitoring-network-throughput/2017-07-net-02.png&#34;
	width=&#34;1014&#34;
	height=&#34;471&#34;
	srcset=&#34;https://mike42.me/blog/2018-08-monitoring-network-throughput/2017-07-net-02_hu_25c426a955c398a4.png 480w, https://mike42.me/blog/2018-08-monitoring-network-throughput/2017-07-net-02_hu_7d50b17c6356d9d3.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;215&#34;
		data-flex-basis=&#34;516px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This table is from a Sagemcom F@ST 3864, which is a consumer-grade router. It has no SNMP interface, so the only way to get these metrics is to query &lt;code&gt;/statsifc.html&lt;/code&gt; and &lt;code&gt;/info.html&lt;/code&gt; from the LAN.&lt;/p&gt;
&lt;h2 id=&#34;getting-the-data&#34;&gt;Getting the data
&lt;/h2&gt;&lt;p&gt;I can derive throughput metrics for the uplink if I scrape these metrics every few seconds and load them into a time-series database. To do this, I wrote &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/network-speed-graphs/tree/master/exporter&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;a small adapter&lt;/a&gt; (called an &amp;ldquo;exporter&amp;rdquo; in Prometheus lingo), which exposed the metrics in a more structured way.&lt;/p&gt;
&lt;p&gt;The result was a web page on the Raspberry Pi, which returns interface data like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# HELP lan_network_receive_bytes Received bytes for network interface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# TYPE lan_network_receive_bytes gauge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_receive_bytes&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth0&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_receive_bytes&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth1&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_receive_bytes&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth2&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_receive_bytes&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth3&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_receive_bytes&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;wl0&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 737476060.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# HELP lan_network_send_bytes Sent bytes for network interface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# TYPE lan_network_send_bytes gauge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_send_bytes&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth0&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 363957004.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_send_bytes&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth1&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_send_bytes&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth2&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_send_bytes&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth3&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_send_bytes&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;wl0&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 2147483647.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# HELP lan_network_receive_packets Received packets for network interface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# TYPE lan_network_receive_packets gauge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth0&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;transfer&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 1766250.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth0&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth0&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;drop&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;transfer&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;drop&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth2&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;transfer&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth2&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth2&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;drop&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth3&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;transfer&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth3&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth3&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;drop&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;wl0&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;transfer&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 6622351.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;wl0&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;wl0&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;drop&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# HELP lan_network_send_packets Sent packets for network interface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# TYPE lan_network_send_packets gauge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth0&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;transfer&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 3148577.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth0&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth0&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;drop&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;transfer&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;drop&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth2&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;transfer&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth2&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth2&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;drop&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth3&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;transfer&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth3&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth3&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;drop&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;wl0&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;transfer&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 8803737.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;wl0&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;wl0&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;drop&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# HELP wan_network_receive_bytes Received bytes for network interface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# TYPE wan_network_receive_bytes gauge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_receive_bytes&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp2.1&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 3013958333.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_receive_bytes&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ptm0.1&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_receive_bytes&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth4.3&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_receive_bytes&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp1.1&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_receive_bytes&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp3.2&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# HELP wan_network_send_bytes Sent bytes for network interface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# TYPE wan_network_send_bytes gauge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_send_bytes&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp2.1&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 717118493.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_send_bytes&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ptm0.1&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_send_bytes&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth4.3&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_send_bytes&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp1.1&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_send_bytes&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp3.2&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# HELP wan_network_receive_packets Received packets for network interface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# TYPE wan_network_receive_packets gauge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp2.1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;transfer&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 11525693.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp2.1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp2.1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;drop&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ptm0.1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;transfer&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ptm0.1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ptm0.1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;drop&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth4.3&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;transfer&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth4.3&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth4.3&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;drop&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp1.1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;transfer&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp1.1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp1.1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;drop&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp3.2&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;transfer&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp3.2&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_receive_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp3.2&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;drop&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# HELP wan_network_send_packets Sent packets for network interface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# TYPE wan_network_send_packets gauge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp2.1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;transfer&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 7728904.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp2.1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp2.1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;drop&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ptm0.1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;transfer&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ptm0.1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ptm0.1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;drop&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth4.3&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;transfer&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth4.3&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;eth4.3&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;drop&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp1.1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;transfer&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp1.1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp1.1&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;drop&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp3.2&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;transfer&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp3.2&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wan_network_send_packets&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;device&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ppp3.2&amp;#34;&lt;/span&gt;,disposition&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;drop&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# HELP adsl_attainable_rate_down_kbps ADSL Attainable Rate down (Kbps)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# TYPE adsl_attainable_rate_down_kbps gauge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;adsl_attainable_rate_down_kbps 19708.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# HELP adsl_attainable_rate_up_kbps ADSL Attainable Rate up (Kbps)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# TYPE adsl_attainable_rate_up_kbps gauge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;adsl_attainable_rate_up_kbps 1087.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# HELP adsl_rate_down_kbps ADSL Rate down (Kbps)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# TYPE adsl_rate_down_kbps gauge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;adsl_rate_down_kbps 18175.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# HELP adsl_rate_up_kbps ADSL Rate up (Kbps)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# TYPE adsl_rate_up_kbps gauge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;adsl_rate_up_kbps 1087.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# HELP process_virtual_memory_bytes Virtual memory size in bytes.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# TYPE process_virtual_memory_bytes gauge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;process_virtual_memory_bytes 34197504.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# HELP process_resident_memory_bytes Resident memory size in bytes.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# TYPE process_resident_memory_bytes gauge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;process_resident_memory_bytes 22441984.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# TYPE process_start_time_seconds gauge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;process_start_time_seconds 1497148890.92
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# TYPE process_cpu_seconds_total counter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;process_cpu_seconds_total 3254.92
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# HELP process_open_fds Number of open file descriptors.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# TYPE process_open_fds gauge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;process_open_fds 7.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# HELP process_max_fds Maximum number of open file descriptors.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# TYPE process_max_fds gauge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;process_max_fds 1024.0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I then deployed Prometheus to the same Raspberry Pi, and configured it to read these metrics every few seconds by editing &lt;code&gt;prometheus.yml&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;global:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  scrape_interval: 5s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;scrape_configs:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - job_name: net
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    static_configs:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    - targets: [&amp;#34;localhost:8000&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;making-some-queries&#34;&gt;Making some queries
&lt;/h2&gt;&lt;p&gt;Prometheus has a query language, which I find similar to spreadsheet formulas. You can enter a query directly into the web interface to get a graph or data table.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-08-monitoring-network-throughput/2017-07-net-03.png&#34;
	width=&#34;2502&#34;
	height=&#34;1236&#34;
	srcset=&#34;https://mike42.me/blog/2018-08-monitoring-network-throughput/2017-07-net-03_hu_b79dee87ca361bcc.png 480w, https://mike42.me/blog/2018-08-monitoring-network-throughput/2017-07-net-03_hu_9d8165cd3c02a52f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;202&#34;
		data-flex-basis=&#34;485px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I settled on these queries to get the data I needed. They show me the maximum attainable line rate, actual sync rate, and current throughput over the WAN interface.&lt;/p&gt;
&lt;h3 id=&#34;download-rate&#34;&gt;Download rate
&lt;/h3&gt;&lt;p&gt;Throughput:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rate(wan_network_receive_bytes{device=&amp;#34;ppp2.1&amp;#34;}[10s])*8/1024/1024
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ADSL attainable:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;adsl_attainable_rate_down_kbps/1024
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ADSL sync:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;adsl_rate_down_kbps/1024
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;upload-rate&#34;&gt;Upload rate
&lt;/h3&gt;&lt;p&gt;Usage:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rate(wan_network_send_bytes{device=&amp;#34;ppp2.1&amp;#34;}[10s])*8/1024/1024
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ADSL attainable:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;adsl_attainable_rate_up_kbps/1024
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ADSL sync:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;adsl_rate_up_kbps/1024
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;onto-a-dashboard&#34;&gt;Onto a dashboard
&lt;/h2&gt;&lt;p&gt;I then deployed the last component in this setup, Grafana, to the Raspberry Pi. This tool lets you save your queries on a dashboard.&lt;/p&gt;
&lt;p&gt;I made two plots, one for uploads, and one for downloads:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-08-monitoring-network-throughput/2017-07-net-04.png&#34;
	width=&#34;2412&#34;
	height=&#34;1208&#34;
	srcset=&#34;https://mike42.me/blog/2018-08-monitoring-network-throughput/2017-07-net-04_hu_f53c6b8b114bd054.png 480w, https://mike42.me/blog/2018-08-monitoring-network-throughput/2017-07-net-04_hu_77a9e5b0cd10bc01.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;199&#34;
		data-flex-basis=&#34;479px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;By saturating the link with traffic (such as when running a speed test), it was now possible to compare the actual network speed with the ADSL sync speed.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-08-monitoring-network-throughput/2017-07-net-06.png&#34;
	width=&#34;2410&#34;
	height=&#34;1255&#34;
	srcset=&#34;https://mike42.me/blog/2018-08-monitoring-network-throughput/2017-07-net-06_hu_39f6cc2704ba82cb.png 480w, https://mike42.me/blog/2018-08-monitoring-network-throughput/2017-07-net-06_hu_1c10106003a491e6.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;192&#34;
		data-flex-basis=&#34;460px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;In my case, the best attainable network speed changed depending on the time of day, while the ADSL sync speed was constant. That&amp;rsquo;s a simple case of congestion.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;ve deployed a few tiny Prometheus setups like this, because of how simple it is to work with new sources of metrics. It&amp;rsquo;s designed for much larger setups than an individual router, so it&amp;rsquo;s a worthwhile tool to be familiar with. Data is always a good reality-check for your assumptions, of course.&lt;/p&gt;
&lt;p&gt;This setup had the level of security that you would expect of a Raspberry Pi project (none), and crashed after 4 days because I did didn&amp;rsquo;t configure Grafana for a RAM-limited environment. It was still a useful learning exercise, so I uploaded the python and Ansible code to GitHub at &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/network-speed-graphs&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/network-speed-graphs&lt;/a&gt;.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to export a Maildir email inbox as a CSV file</title>
        <link>https://mike42.me/blog/2018-07-how-to-export-a-maildir-email-inbox-as-a-csv-file</link>
        <pubDate>Thu, 12 Jul 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-07-how-to-export-a-maildir-email-inbox-as-a-csv-file</guid>
        <description>&lt;p&gt;I&amp;rsquo;ve often thought it would be useful to have an &amp;ldquo;Export as CSV&amp;rdquo; button on my inbox, and recently had an excuse to implement one.&lt;/p&gt;
&lt;p&gt;I needed to parse the &lt;code&gt;Subject&lt;/code&gt; of each email coming from an automated process, but the inbox was in the &lt;code&gt;Maildir&lt;/code&gt; format, and I needed something more useful for data interchange.&lt;/p&gt;
&lt;p&gt;So I wrote a utility, &lt;code&gt;mail2csv&lt;/code&gt;, to export the &lt;code&gt;Maildir&lt;/code&gt; as CSV file, which many existing tools can work with. It produces one row per email, and one column per email header:&lt;/p&gt;
&lt;p&gt;The basic usage is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ mail2csv example/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Date,Subject,From
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#34;Wed, 16 May 2018 20:05:16 +0000&amp;#34;,An email,Bob &amp;lt;bob@example.com&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#34;Wed, 16 May 2018 20:07:52 +0000&amp;#34;,Also an email,Alice &amp;lt;alice@example.com&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can select any header with the &lt;code&gt;--headers&lt;/code&gt; field, which accepts globs:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ mail2csv example/ --headers Message-ID Date Subject
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Message-ID,Date,Subject
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;lt;89125@example.com&amp;gt;,&amp;#34;Wed, 16 May 2018 20:05:16 +0000&amp;#34;,An email
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;lt;180c6@example.com&amp;gt;,&amp;#34;Wed, 16 May 2018 20:07:52 +0000&amp;#34;,Also an email
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you&amp;rsquo;re not sure which headers your emails have, then you can make a CSV with all the headers, and just read the first line:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ mail2csv  example/ --headers &amp;#39;*&amp;#39; | head -n1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can find the Python code for this tool at &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/mail2csv&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/mail2csv&lt;/a&gt; on GitHub.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to make HHVM 3.21 identify itself as PHP 7</title>
        <link>https://mike42.me/blog/2018-07-how-to-make-hhvm-3-21-identify-itself-as-php-7</link>
        <pubDate>Thu, 05 Jul 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-07-how-to-make-hhvm-3-21-identify-itself-as-php-7</guid>
        <description>&lt;p&gt;HHVM is an alternative runtime for PHP, which I try to maintain compatibility with.&lt;/p&gt;
&lt;p&gt;I recently upgraded a project to PHPUnit 6, and the tests started failing on &lt;code&gt;hhvm-3.21&lt;/code&gt; with this error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This version of PHPUnit is supported on PHP 7.0 and PHP 7.1.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;You are using PHP 5.6.99-hhvm (/usr/bin/hhvm).
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Although HHVM supports many PHP 7 features, it is identifying itself as PHP 5.6. The &lt;a class=&#34;link&#34; href=&#34;https://hhvm.com/blog/10859/php-7-support&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;official documentation&lt;/a&gt; includes a setting for enabling additional PHP 7 features, which also sets the reported version.&lt;/p&gt;
&lt;p&gt;This project was building on Travis CI, so adding this one-liner to &lt;code&gt;.travis.yml&lt;/code&gt; sets this flag in the configuration, and the issue goes away:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;before_script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;bash -c &amp;#39;if [[ $TRAVIS_PHP_VERSION == hhvm* ]]; then echo &amp;#34;hhvm.php7.all = 1&amp;#34; | sudo tee -a /etc/hhvm/php.ini; fi&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m writing about this for other developers who hit the same issue. The current releases of HHVM don&amp;rsquo;t seem to have this issue, so hopefully this work-around is temporary.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to check PHP code style in a continuous integration environment</title>
        <link>https://mike42.me/blog/2018-06-how-to-check-php-code-style-in-a-continuous-integration-environment</link>
        <pubDate>Thu, 28 Jun 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-06-how-to-check-php-code-style-in-a-continuous-integration-environment</guid>
        <description>&lt;p&gt;I&amp;rsquo;m going to write a bit today about &lt;a class=&#34;link&#34; href=&#34;https://github.com/squizlabs/PHP_CodeSniffer&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;PHP_CodeSniffer&lt;/a&gt;, which is a tool for detecting PHP style violations.&lt;/p&gt;
&lt;h2 id=&#34;background&#34;&gt;Background
&lt;/h2&gt;&lt;p&gt;Convention is good. It&amp;rsquo;s like following the &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Principle_of_least_astonishment&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;principle of least surprise&lt;/a&gt; in software design, but for your developer audience.&lt;/p&gt;
&lt;p&gt;PHP has two code standards that I see in the wild:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://pear.php.net/manual/en/standards.php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;PEAR code standard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.php-fig.org/psr/psr-2/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;PSR-2 code style&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are writing new PHP code, or refactoring code that follows no discernible standard, you should use the PSR-2 code style.&lt;/p&gt;
&lt;p&gt;I use PHP_CodeSniffer on a few projects to stop the build early if the code is not up to standard. It has the ability to fix the formatting problems it finds, so it is not a difficult test to clear.&lt;/p&gt;
&lt;h2 id=&#34;add-php_codesniffer-to-your-project&#34;&gt;Add PHP_CodeSniffer to your project
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;m assuming that you are already using &lt;code&gt;composer&lt;/code&gt; to manage your PHP dependencies.&lt;/p&gt;
&lt;p&gt;Ensure you are specifying your minimum PHP version in your &lt;code&gt;composer.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;#34;require&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;php&amp;#34;: &amp;#34;&amp;gt;=7.0.0&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, add &lt;code&gt;squizlabs/php_codesniffer&lt;/code&gt; as a development dependency of your project:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;composer require --dev squizlabs/php_codesniffer
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;check-your-code&#34;&gt;Check your code
&lt;/h2&gt;&lt;p&gt;I use this command to check the &lt;code&gt;src&lt;/code&gt; folder. It can be run locally or on a CI box:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;php vendor/bin/phpcs --standard=psr2 src/ -n
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will return nonzero if there are problems with the code style, which should stop the build on most systems.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;-n&lt;/code&gt; flag avoids less severe &amp;ldquo;warnings&amp;rdquo;. One of these is the &amp;ldquo;Line exceeds 120 characters&amp;rdquo;, which can be difficult to completely eliminate.&lt;/p&gt;
&lt;h2 id=&#34;fixing-the-style&#34;&gt;Fixing the style
&lt;/h2&gt;&lt;p&gt;Running the &lt;code&gt;phpcbf&lt;/code&gt; command with the same arguments will correct simple formatting issues:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;php vendor/bin/phpcs --standard=psr2 src/ -n
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;travis-ci-example&#34;&gt;Travis CI example
&lt;/h2&gt;&lt;p&gt;A full &lt;code&gt;.travis.yml&lt;/code&gt; which uses this would look like this (adapted from &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php/commit/bd9d5b4257f012052e4f2d75fc3ec9f9fc208da5#diff-354f30a63fb0907d4ad57269548329e3&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;here&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;language&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;php&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;php&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;7.0&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;7.1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;m&#34;&gt;7.2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;install&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;composer install&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;php vendor/bin/phpcs --standard=psr2 test/ -n&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you are running a PHP project without any sort of build, then this is a good place to start: Aside from style, this checks that dependencies can be installed on a supported range of PHP versions, and will also break if there are files with syntax errors.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Make better CLI progress bars with Unicode block characters</title>
        <link>https://mike42.me/blog/2018-06-make-better-cli-progress-bars-with-unicode-block-characters</link>
        <pubDate>Thu, 14 Jun 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-06-make-better-cli-progress-bars-with-unicode-block-characters</guid>
        <description>&lt;p&gt;As a programmer, you might add a progress bar so that the user has feedback while they wait for a slow task.&lt;/p&gt;
&lt;p&gt;If you are writing a console (CLI) application, then you need to make your progress bars from text. A good command-line progress bar should update in small increments, like this example:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-06-make-better-cli-progress-bars-with-unicode-block-characters/2018-06-progress-bar-animated.gif&#34;
	width=&#34;425&#34;
	height=&#34;72&#34;
	
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;590&#34;
		data-flex-basis=&#34;1416px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This uses &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Block_Elements&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Unicode Block Elements&lt;/a&gt; to give the progress bar a higher resolution.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Code&lt;/th&gt;
          &lt;th&gt;Character&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;U+2588&lt;/td&gt;
          &lt;td&gt;█&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;U+2589&lt;/td&gt;
          &lt;td&gt;▉&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;U+258A&lt;/td&gt;
          &lt;td&gt;▊&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;U+258B&lt;/td&gt;
          &lt;td&gt;▋&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;U+258C&lt;/td&gt;
          &lt;td&gt;▌&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;U+258D&lt;/td&gt;
          &lt;td&gt;▍&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;U+258E&lt;/td&gt;
          &lt;td&gt;▎&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;U+258F&lt;/td&gt;
          &lt;td&gt;▏&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A lot of applications use plain ASCII in their progress bars. The progress bar in wget, for example, uses &lt;code&gt;===&amp;gt;&lt;/code&gt; characters only, like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-06-make-better-cli-progress-bars-with-unicode-block-characters/2018-06-progress-bar-text.png&#34;
	width=&#34;1296&#34;
	height=&#34;240&#34;
	srcset=&#34;https://mike42.me/blog/2018-06-make-better-cli-progress-bars-with-unicode-block-characters/2018-06-progress-bar-text_hu_5fd3d0c4d41743b3.png 480w, https://mike42.me/blog/2018-06-make-better-cli-progress-bars-with-unicode-block-characters/2018-06-progress-bar-text_hu_f8fbb9f915f31c22.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;540&#34;
		data-flex-basis=&#34;1296px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Progress bars made from ASCII characters like &lt;code&gt;=&lt;/code&gt; and &lt;code&gt;#&lt;/code&gt; signs are very common, most likely because of the historical portability issues around non-ASCII text. Nowadays, UTF-8 support is ubiquitous, and it&amp;rsquo;s pointless to adhere to such limitations.&lt;/p&gt;
&lt;h2 id=&#34;example-better-progress-bars-in-python&#34;&gt;Example: Better progress bars in python
&lt;/h2&gt;&lt;p&gt;The animation at the top of this blog post is a simple python script.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;sys&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;progress_bar&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ProgressBar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;Example usage of ProgressBar class
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Doing work&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ProgressBar&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sys&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stdout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;progress&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;range&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;800&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;progress&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;update&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;800&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sleep&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;0.05&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Done.&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The script &lt;code&gt;progress_bars.py&lt;/code&gt;, written for Python 3, contains a class that allows the progress bar to be created and drawn on different types of terminals.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;abc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;math&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;shutil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;sys&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;typing&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TextIO&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;Produce progress bar with ANSI code output.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;ProgressBar&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;object&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;fm&#34;&gt;__init__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;target&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TextIO&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sys&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stdout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_target&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_text_only&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_target&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;isatty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_update_width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;fm&#34;&gt;__enter__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;fm&#34;&gt;__exit__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;exc_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;exc_val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;exc_tb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;exc_type&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;c1&#34;&gt;# Set to 100% for neatness, if no exception is thrown&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;update&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_text_only&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;c1&#34;&gt;# ANSI-output should be rounded off with a newline&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_target&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_target&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flush&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;pass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;_update_width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;_&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shutil&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_terminal_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;update&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;progress&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;float&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;# Update width in case of resize&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_update_width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;# Progress bar itself&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;c1&#34;&gt;# No label in excessively small terminal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;percent_str&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;progress_bar_str&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ProgressBar&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;progress_bar_str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;progress&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;elif&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;40&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;c1&#34;&gt;# No padding at smaller size&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;percent_str&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{:6.2f}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; %&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;progress&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;progress_bar_str&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ProgressBar&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;progress_bar_str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;progress&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;11&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;c1&#34;&gt;# Standard progress bar with padding and label&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;percent_str&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{:6.2f}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; %&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;progress&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;  &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;progress_bar_str&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ProgressBar&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;progress_bar_str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;progress&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;21&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;# Write output&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_text_only&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_target&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;progress_bar_str&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;percent_str&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_target&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flush&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_target&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\033&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;[G&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;progress_bar_str&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;percent_str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_target&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flush&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nd&#34;&gt;@staticmethod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;progress_bar_str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;progress&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;float&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;width&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;# 0 &amp;lt;= progress &amp;lt;= 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;progress&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;min&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;max&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;progress&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;whole_width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;math&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;floor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;progress&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;remainder_width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;progress&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;part_width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;math&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;floor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;remainder_width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;part_char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;▏&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;▎&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;▍&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;▌&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;▋&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;▊&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;▉&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;][&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;part_width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;whole_width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;n&#34;&gt;part_char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;[&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;█&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;whole_width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;part_char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;whole_width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;]&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Aside from the use of box drawing characters, this script includes a few other things which a good progress bar should implement:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Resize the progress bar when you resize the terminal&lt;/li&gt;
&lt;li&gt;Simplify the progress bar on very small terminals&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t print ANSI terminal codes if the script is not connected to a terminal&lt;/li&gt;
&lt;li&gt;Round off to 100% once the use of the progress bar completes without error&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After writing this, I discovered that the &lt;a class=&#34;link&#34; href=&#34;https://github.com/verigak/progress&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;progress&lt;/a&gt; pypi package can also use these box characters, so I haven&amp;rsquo;t packaged this code up. I haven&amp;rsquo;t used &lt;code&gt;progress&lt;/code&gt; yet, but if you want better progress bars, then you might like to evaluate it for your own application.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to create effective PHP project documentation with Read the Docs</title>
        <link>https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs</link>
        <pubDate>Thu, 07 Jun 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs</guid>
        <description>&lt;p&gt;Documentation is one of the ways that software projects can communicate information to their users. Effective documentation is high-quality, meaning that it&amp;rsquo;s complete, accurate, and up-to-date. At least for open source libraries, it also means that you can find it with a search engine. For many small PHP projects, the reality is very far removed from the ideal.&lt;/p&gt;
&lt;p&gt;Read the Docs (&lt;a class=&#34;link&#34; href=&#34;https://readthedocs.io/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;readthedocs.io&lt;/a&gt;) makes it easy to host an up-to-date copy of your project&amp;rsquo;s documentation online. There are around 2,000 PHP projects which host their documentation on the site, which makes PHP the &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2018-05-quick-statistics-about-documentation-hosted-on-read-the-docs&#34; &gt;third most popular programming language&lt;/a&gt; for projects on the site.&lt;/p&gt;
&lt;p&gt;This post covers the process that is used to automatically publish the documentation for the &lt;a class=&#34;link&#34; href=&#34;https://gfx-php.readthedocs.io/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;gfx-php&lt;/a&gt; PHP graphics library, which is one of those 2000 projects. You should consider using this setup as a template if you your project is small enough that it does not have its own infrastructure.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-php-apidocumentation-result.png&#34;
	width=&#34;2518&#34;
	height=&#34;1496&#34;
	srcset=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-php-apidocumentation-result_hu_7d3bfa666ced5364.png 480w, https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-php-apidocumentation-result_hu_ccfe8d2d698c9a56.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;168&#34;
		data-flex-basis=&#34;403px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;basic-concept&#34;&gt;Basic concept
&lt;/h2&gt;&lt;p&gt;Typically, people are using Read the Docs with a tool called Sphinx. If you are writing in Python, it&amp;rsquo;s also possible to use the &lt;a class=&#34;link&#34; href=&#34;http://www.sphinx-doc.org/en/master/ext/autodoc.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;autodoc&lt;/a&gt; Sphinx plugin to add API documentation, based on docstrings in the code.&lt;/p&gt;
&lt;p&gt;&lt;div class=&#34;img-canvas-outer&#34;&gt;
&lt;a href=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-autodoc-1.svg&#34; class=&#34;img-canvas-link  img-sm&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-autodoc-1.svg&#34;
	
	
	
	loading=&#34;lazy&#34;
	
	
	    class=&#34;img-canvas-inner&#34; 
	
&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;PHP programmers are already spoiled for choice if they want to produce HTML documentation from their code. These tools all have huge PHP user bases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/FriendsOfPHP/Sami&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Sami&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.phpdoc.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;phpDocumentor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/doxygen/doxygen&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Doxygen&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These will each output their own HTML, which is only useful if you want to self-host the documentation. I wanted a tool that was more like &amp;ldquo;autodoc for PHP&amp;rdquo;, so that I can have my API docs magically appear in Sphinx output that is hosted on Read the Docs.&lt;/p&gt;
&lt;p&gt;Doxygen is the most useful tool for this purpose, because it has a stable XML output format and good-enough PHP support. I decided to write a tool which to take the Doxygen XML info and generate rest for Sphinx:&lt;/p&gt;
&lt;p&gt;&lt;div class=&#34;img-canvas-outer&#34;&gt;
&lt;a href=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-phpdoxy2sphinx.svg&#34; class=&#34;img-canvas-link  &#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-phpdoxy2sphinx.svg&#34;
	
	
	
	loading=&#34;lazy&#34;
	
	
	    class=&#34;img-canvas-inner&#34; 
	
&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;This introduces some extra tools, which looks complex at first. The stack is geared towards running within the Read the Docs build environment, so most developers can treat it as a black box after the initial setup:&lt;/p&gt;
&lt;p&gt;&lt;div class=&#34;img-canvas-outer&#34;&gt;
&lt;a href=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-php-hosted-1.svg&#34; class=&#34;img-canvas-link  img-sm&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-php-hosted-1.svg&#34;
	
	
	
	loading=&#34;lazy&#34;
	
	
	    class=&#34;img-canvas-inner&#34; 
	
&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;This setup is entirely hosted with free cloud services, so you don&amp;rsquo;t need to run any applications on your own hardware.&lt;/p&gt;
&lt;h2 id=&#34;tools-to-install-on-local-workstation&#34;&gt;Tools to install on local workstation
&lt;/h2&gt;&lt;p&gt;First, we will set up each of these tools locally, so that we know everything is working before we upload it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Doxygen&lt;/li&gt;
&lt;li&gt;Sphinx&lt;/li&gt;
&lt;li&gt;doxyphp2sphinx&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;doxygen&#34;&gt;Doxygen
&lt;/h3&gt;&lt;p&gt;Doxygen can read PHP files to extract class names, documentation and method signatures. Linux and Mac install this from most package managers (&lt;code&gt;apt-get&lt;/code&gt;, &lt;code&gt;dnf&lt;/code&gt; or &lt;code&gt;brew&lt;/code&gt;) under the name &lt;code&gt;doxygen&lt;/code&gt;, while Windows users need to chase down binaries.&lt;/p&gt;
&lt;p&gt;In your repo, make a sub-folder called &lt;code&gt;docs/&lt;/code&gt;, and create a &lt;code&gt;Doxyfile&lt;/code&gt; with some defaults:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir docs/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;doxygen -g Doxyfile
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You need to edit the configuration to make it suitable or generating XML output for your PHP project. The version of Doxygen used here is 1.8.13, where you only need to change a few values to set Doxygen to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Recursively search PHP files in your project&amp;rsquo;s source folder&lt;/li&gt;
&lt;li&gt;Generate XML and HTML only&lt;/li&gt;
&lt;li&gt;Log warnings to a file&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For a typical project, these settings are:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;PROJECT_NAME&lt;/span&gt;           &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Example Project&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;INPUT&lt;/span&gt;                  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; ../src
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;WARN_LOGFILE&lt;/span&gt;           &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; warnings.log
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;RECURSIVE&lt;/span&gt;              &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; YES
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;USE_MDFILE_AS_MAINPAGE&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; ../README.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;GENERATE_LATEX&lt;/span&gt;         &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; NO
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;GENERATE_XML&lt;/span&gt;           &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; YES
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once you set these in &lt;code&gt;Doxyfile&lt;/code&gt;, you can run Doxygen to generate HTML and XML output.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ doxygen
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Doxygen will pick up most method signatures automatically, and you can add to them via &lt;code&gt;docblocks&lt;/code&gt;, which work along the same lines as &lt;code&gt;docstrings&lt;/code&gt; in Python. Read &lt;a class=&#34;link&#34; href=&#34;https://www.stack.nl/~dimitri/doxygen/manual/docblocks.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Doxygen: Documenting the Code&lt;/a&gt; to learn the syntax if you have not used a documentation generator in a curly-bracket language before.&lt;/p&gt;
&lt;p&gt;The Doxygen HTML will never be published, but you might need to read it to see how well Doxygen understands your code.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-doxy-html.png&#34;
	width=&#34;2782&#34;
	height=&#34;1838&#34;
	srcset=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-doxy-html_hu_f88934c270b4454e.png 480w, https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-doxy-html_hu_30bc9d649f00fca.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;151&#34;
		data-flex-basis=&#34;363px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The XML output is much more useful for our purposes. It contains the same information, and we will read it to generate pages of documentation for Sphinx to render.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-doxy-xml-1.png&#34;
	width=&#34;2662&#34;
	height=&#34;1170&#34;
	srcset=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-doxy-xml-1_hu_a01e94b17c2c083f.png 480w, https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-doxy-xml-1_hu_a2b1ceb72376c446.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;227&#34;
		data-flex-basis=&#34;546px&#34;
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;sphinx&#34;&gt;Sphinx
&lt;/h3&gt;&lt;p&gt;Sphinx is the tool that we will use to render the final HTML output. If you haven&amp;rsquo;t used it before, then see the official &lt;a class=&#34;link&#34; href=&#34;http://www.sphinx-doc.org/en/master/usage/quickstart.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Getting Started&lt;/a&gt; page.&lt;/p&gt;
&lt;p&gt;We are using Sphinx because it can be executed by online services like Read the Docs. It uses the reStructuredText format, which is a whole lot more complex than Markdown, but supports cross-references. I&amp;rsquo;ll only describe these steps briefly, because there are existing how-to guides on making Sphinx work for manually-written PHP documentation elsewhere on the Internet, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.sitepoint.com/using-sphinx-for-php-project-documentation/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Using Sphinx for PHP Project Documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;http://mark-story.com/posts/view/sphinx-phpdomain-released&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Sphinx PHPdomain released&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Still in the &lt;code&gt;docs&lt;/code&gt; folder with your Doxyfile, create and render an empty Sphinx project.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pip install sphinx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sphinx-quickstart --quiet --project example_project --author example_bob
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make html
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The generated HTML will initially appear like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-example-project.png&#34;
	width=&#34;2402&#34;
	height=&#34;910&#34;
	srcset=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-example-project_hu_6ea12e70281f6a0f.png 480w, https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-example-project_hu_f4f1388e7f21b5cc.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;263&#34;
		data-flex-basis=&#34;633px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;We need to customize this in a way that adds PHP support. The quickest way is to drop this text into &lt;code&gt;requirements.txt&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Sphinx==1.7.4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sphinx-rtd-theme==0.3.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sphinxcontrib-phpdomain==0.4.1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;doxyphp2sphinx&amp;gt;=1.0.1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then update &lt;code&gt;config.py&lt;/code&gt; to set &lt;code&gt;extensions&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;extensions&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;s2&#34;&gt;&amp;#34;sphinxcontrib.phpdomain&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then also set the theme.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;html_theme&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;sphinx_rtd_theme&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Lastly, add this to the end of the file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# PHP Syntax&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;sphinx.highlighting&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;lexers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;pygments.lexers.web&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PhpLexer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;lexers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;php&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PhpLexer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;startinline&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;linenos&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;lexers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;php-annotations&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PhpLexer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;startinline&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;linenos&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Set domain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;primary_domain&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;php&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next drop this contents in &lt;code&gt;_templates/breadcrumbs.html&lt;/code&gt; (&lt;a class=&#34;link&#34; href=&#34;http://docs.readthedocs.io/en/latest/guides/remove-edit-buttons.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;explanation&lt;/a&gt;)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;%-&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;extends&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sphinx_rtd_theme/breadcrumbs.html&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;block&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;breadcrumbs_aside&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;endblock&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then finally re-install dependencies and re-build:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pip install -r requirements.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make html
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The HTML output under &lt;code&gt;_build&lt;/code&gt; will now appear as:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-example-project-styled.png&#34;
	width=&#34;2296&#34;
	height=&#34;1120&#34;
	srcset=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-example-project-styled_hu_51aa0acd0973dbdd.png 480w, https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-example-project-styled_hu_fc24c61d3a75a17e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;205&#34;
		data-flex-basis=&#34;492px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This setup gives us three things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The documentation looks the same as Read the Docs.&lt;/li&gt;
&lt;li&gt;We can use PHP snippets and class documentation.&lt;/li&gt;
&lt;li&gt;There are no &amp;lsquo;Edit&amp;rsquo; links, which is important because some of the files will be generated in the next steps.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;doxyphp2sphinx&#34;&gt;doxyphp2sphinx
&lt;/h3&gt;&lt;p&gt;The &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/doxyphp2sphinx&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;doxyphp2sphinx&lt;/a&gt; tool will generate &lt;code&gt;.rst&lt;/code&gt; files from the Doxygen XML files. This was installed from your &lt;code&gt;requirements.txt&lt;/code&gt; in the last step, but you can also install it standalone via pip:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pip install doxyphp2sphinx
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The only thing you need to specify is the name of the namespace that you are documenting, using &lt;code&gt;::&lt;/code&gt; as a separator.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;doxyphp2sphinx FooCorp::Example
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This command will read the &lt;code&gt;xml/&lt;/code&gt; subdirectory, and will create &lt;code&gt;api.rst&lt;/code&gt;. It will fill the &lt;code&gt;api/&lt;/code&gt; directory with documentation for each class in the &lt;code&gt;\FooCorp\Example&lt;/code&gt; namespace.&lt;/p&gt;
&lt;p&gt;To verify that this has worked, check your class structure:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ tree ../src
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;../src
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── Dooverwhacky.php
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;└── Widget.php
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You should have documentation for each of these:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ tree xml/ -P &amp;#39;class*&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;xml/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── classFooCorp_1_1Example_1_1Dooverwhacky.xml
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;└── classFooCorp_1_1Example_1_1Widget.xml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And if you have the correct namespace name, you will have &lt;code&gt;.rst&lt;/code&gt; files for each as well:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ tree api
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;api
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── dooverwhacky.rst
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;└── widget.rst
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, add a reference to &lt;code&gt;api.rst&lt;/code&gt; somewhere in &lt;code&gt;index.rst&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.. toctree::
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   :maxdepth: 2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   :caption: API Documentation
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   Classes &amp;lt;api.rst&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And re-compile:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make html
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can now navigate to your classes in the HTML documentation.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-example-apidocs.png&#34;
	width=&#34;2274&#34;
	height=&#34;966&#34;
	srcset=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-example-apidocs_hu_17bb8607c7a45271.png 480w, https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-example-apidocs_hu_a758d72e2c7df3e4.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;235&#34;
		data-flex-basis=&#34;564px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The quality of the generated class documentation can be improved by adding docstrings. An example of the generated documentation for a method is:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-php-method-docs.png&#34;
	width=&#34;1398&#34;
	height=&#34;450&#34;
	srcset=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-php-method-docs_hu_dae401b510abc2b6.png 480w, https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-php-method-docs_hu_52a2ae20df03290d.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;310&#34;
		data-flex-basis=&#34;745px&#34;
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;writing-documentation&#34;&gt;Writing documentation
&lt;/h3&gt;&lt;p&gt;As you add pages to your documentation, you can include PHP snippets and reference the usage of your classes.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-mysql&#34; data-lang=&#34;mysql&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;..&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;code&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;block&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;php&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;   
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;php&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;echo&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello World&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Lorem&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ipsum&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dolor&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sit&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Dooverwhacky&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;foo&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bar&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;baz&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;meth&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Widget&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;getFeatureCount&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will create syntax highlighting for your examples and inline links to the generated API docs.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-example-docs.png&#34;
	width=&#34;1482&#34;
	height=&#34;274&#34;
	srcset=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-example-docs_hu_8e02e03f81b55d1a.png 480w, https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-example-docs_hu_3d92a1e7ba55f29.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;540&#34;
		data-flex-basis=&#34;1298px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Beyond this, you will need to learn some reStructuredText. I found &lt;a class=&#34;link&#34; href=&#34;http://docutils.sourceforge.net/docs/user/rst/quickref.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this reference&lt;/a&gt; to be useful.&lt;/p&gt;
&lt;h3 id=&#34;local-docs-build&#34;&gt;Local docs build
&lt;/h3&gt;&lt;p&gt;A full build has these dependencies:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install doxygen make python-pip
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pip install -r docs/requirements.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And these steps:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cd docs/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;doxygen 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;doxyphp2sphinx FooCorp::Example
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make html
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;cloud-tools&#34;&gt;Cloud tools
&lt;/h2&gt;&lt;p&gt;Next, we will take this local build, and run it on a cloud setup instead, using these services.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GitHub&lt;/li&gt;
&lt;li&gt;Read the docs&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;github&#34;&gt;GitHub
&lt;/h3&gt;&lt;p&gt;I will assume that you know how to use Git and GitHub, and that you are creating code that is intended for re-use.&lt;/p&gt;
&lt;p&gt;Add these files to your &lt;code&gt;.gitignore&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docs/_build/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docs/warnings.log
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docs/xml/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docs/html/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Upload the remainder of your repository to GitHub. The &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/gfx-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;gfx-php&lt;/a&gt; project is an example of a working project with all of the correct files included.&lt;/p&gt;
&lt;p&gt;To execute the initial two build steps execute on Read the Docs, add this to the end of &lt;code&gt;docs/conf.py&lt;/code&gt;. Don&amp;rsquo;t forget to update the namespace to match the command you were running locally.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Regenerate API docs via doxygen + doxyphp2sphinx&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;subprocess&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;os&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;read_the_docs_build&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;environ&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;READTHEDOCS&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;True&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;read_the_docs_build&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;subprocess&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;call&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;doxygen&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;Doxyfile&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;subprocess&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;call&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;doxyphp2sphinx&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;FooCorp::Example&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;read-the-docs&#34;&gt;Read the Docs
&lt;/h3&gt;&lt;p&gt;After all this setup, Read the Docs should be able to build the project. Create the project on Read the Docs by using the &lt;strong&gt;Import from GitHub&lt;/strong&gt; option. There are only two settings which need to be set:&lt;/p&gt;
&lt;p&gt;The requirements file location must be &lt;code&gt;docs/requirements.txt&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2016-06-settings-requirements.png&#34;
	width=&#34;2444&#34;
	height=&#34;966&#34;
	srcset=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2016-06-settings-requirements_hu_fccaf168e888e9a7.png 480w, https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2016-06-settings-requirements_hu_75f9e23d24b76798.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;253&#34;
		data-flex-basis=&#34;607px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;And the programming language should be PHP.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-settings-php-sphinx.png&#34;
	width=&#34;2204&#34;
	height=&#34;710&#34;
	srcset=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-settings-php-sphinx_hu_ecbefa2741ada881.png 480w, https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-settings-php-sphinx_hu_3b2cbbc1d895a8e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;310&#34;
		data-flex-basis=&#34;745px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;After this, you can go ahead and run a build.&lt;/p&gt;
&lt;p&gt;As a last step, you will want to ensure &lt;a class=&#34;link&#34; href=&#34;https://docs.readthedocs.io/en/latest/webhooks.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;that you have a Webhook set up&lt;/a&gt; on GitHub to trigger the builds automatically in future.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-readthedocs-webhook.png&#34;
	width=&#34;2174&#34;
	height=&#34;832&#34;
	srcset=&#34;https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-readthedocs-webhook_hu_b54a93e426c5045f.png 480w, https://mike42.me/blog/2018-06-how-to-create-effective-php-project-documentation-with-read-the-docs/2018-06-readthedocs-webhook_hu_21793f049368bb5e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;261&#34;
		data-flex-basis=&#34;627px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;It is emerging as a best practice for small libraries to host their documentation with Read the Docs, but this is not yet common in the PHP world. Larger PHP projects tend to self-host documentation on the project website, but smaller projects will often have no hosted API documentation.&lt;/p&gt;
&lt;p&gt;Once you write your docs, publishing them should be easy! Hopefully this provides a good example of what&amp;rsquo;s possible.&lt;/p&gt;
&lt;h2 id=&#34;acknowledgements&#34;&gt;Acknowledgements
&lt;/h2&gt;&lt;p&gt;Credit where credit is due: The &lt;a class=&#34;link&#34; href=&#34;https://breathe.readthedocs.io/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Breathe&lt;/a&gt; project fills this niche for C++ developers using Doxygen, and has been around for some time. Breathe is in the early stages of adding PHP support, but is not yet ready at the time of writing.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to get a notification when your site appears on HackerNews</title>
        <link>https://mike42.me/blog/2018-05-how-to-get-a-notification-when-your-site-appears-on-hackernews</link>
        <pubDate>Thu, 31 May 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-05-how-to-get-a-notification-when-your-site-appears-on-hackernews</guid>
        <description>&lt;p&gt;A few weeks ago, somebody submitted &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/how-to-use-parallel-to-speed-up-your-work&#34; &gt;this article about GNU parallel&lt;/a&gt; to &lt;a class=&#34;link&#34; href=&#34;https://news.ycombinator.com/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;HackerNews&lt;/a&gt;, and I got a small wave of new visitors trawling my blog.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t actively monitor referrers to this site, so I was oblivious to this until a few days afterward. Aware of the &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Slashdot_effect&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Slashdot Effect&lt;/a&gt;, I thought I should set up some free tools to remind me to log in and check the site&amp;rsquo;s health if it happens again:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://ifttt.com/discover&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;IFTTT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://edavis.github.io/hnrss/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Hacker News RSS feeds&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;hacker-news-rss-feeds&#34;&gt;Hacker News RSS feeds
&lt;/h2&gt;&lt;p&gt;Hacker news does not publish its own RSS feeds, so I had to use a third-party service. I found a URL that would feed me the feed to the latest articles off this site, by searching the &amp;ldquo;url&amp;rdquo; attribute:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;https://hnrss.org/newest?q=mike42.me&amp;amp;search_attrs=url
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This URL gives an RSS feed, as you might expect:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-05-how-to-get-a-notification-when-your-site-appears-on-hackernews/2018-05-rss-example.png&#34;
	width=&#34;1770&#34;
	height=&#34;710&#34;
	srcset=&#34;https://mike42.me/blog/2018-05-how-to-get-a-notification-when-your-site-appears-on-hackernews/2018-05-rss-example_hu_f2f8c6e5aad9388e.png 480w, https://mike42.me/blog/2018-05-how-to-get-a-notification-when-your-site-appears-on-hackernews/2018-05-rss-example_hu_4eb74c8a2144e22e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;249&#34;
		data-flex-basis=&#34;598px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;ifttt&#34;&gt;IFTTT
&lt;/h2&gt;&lt;p&gt;To save me installing and checking a local reader, I set up IFTTT to send me an email when new articles are published to this feed.&lt;/p&gt;
&lt;p&gt;The &amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;https://ifttt.com/applets/147561p-rss-feed-to-email&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;RSS feed to email&lt;/a&gt;&amp;rdquo; applet is perfect for this kind of consumer-grade automation.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-05-how-to-get-a-notification-when-your-site-appears-on-hackernews/2018-05-rss-ifttt-email-example.png&#34;
	width=&#34;3810&#34;
	height=&#34;1466&#34;
	srcset=&#34;https://mike42.me/blog/2018-05-how-to-get-a-notification-when-your-site-appears-on-hackernews/2018-05-rss-ifttt-email-example_hu_36480987c1c1ad22.png 480w, https://mike42.me/blog/2018-05-how-to-get-a-notification-when-your-site-appears-on-hackernews/2018-05-rss-ifttt-email-example_hu_384d86e2a48b19ce.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;259&#34;
		data-flex-basis=&#34;623px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I set it up with the URL, and well, nothing interesting happens. Only &lt;em&gt;new&lt;/em&gt; articles are emailed, so this is expected.&lt;/p&gt;
&lt;h2 id=&#34;example-email&#34;&gt;Example email
&lt;/h2&gt;&lt;p&gt;Since I also use this IFTTT applet to get notifications for other RSS feeds, I do know that it works. Within an hour or two of a new article appearing in the feed, the applet gives you an email from &lt;code&gt;RSS Feed via IFTTT &amp;lt;action@ifttt.com&amp;gt;&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-05-how-to-get-a-notification-when-your-site-appears-on-hackernews/2018-05-rss-ifttt-email-example2.png&#34;
	width=&#34;2640&#34;
	height=&#34;510&#34;
	srcset=&#34;https://mike42.me/blog/2018-05-how-to-get-a-notification-when-your-site-appears-on-hackernews/2018-05-rss-ifttt-email-example2_hu_15d5e7876413873c.png 480w, https://mike42.me/blog/2018-05-how-to-get-a-notification-when-your-site-appears-on-hackernews/2018-05-rss-ifttt-email-example2_hu_dbdd141b4f299d3c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;517&#34;
		data-flex-basis=&#34;1242px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s not exactly a real-time notification, but I know when my posts are being linked from a specific high-traffic site, which is a good start.&lt;/p&gt;
&lt;p&gt;For any site bigger than a personal blog, you might be interested in &lt;em&gt;handling&lt;/em&gt; extra traffic rather than just be vaguely aware of it, but I&amp;rsquo;ll save that for a future post.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Quick statistics about documentation hosted on Read the Docs</title>
        <link>https://mike42.me/blog/2018-05-quick-statistics-about-documentation-hosted-on-read-the-docs</link>
        <pubDate>Thu, 24 May 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-05-quick-statistics-about-documentation-hosted-on-read-the-docs</guid>
        <description>&lt;p&gt;Many open source projects host their online documentation with &lt;a class=&#34;link&#34; href=&#34;https://readthedocs.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Read The Docs&lt;/a&gt;. Since I&amp;rsquo;m currently developing a tool for Read The Docs users, I recently took a look at the types of projects that are hosted there.&lt;/p&gt;
&lt;p&gt;The data in this post is derived from &lt;a class=&#34;link&#34; href=&#34;http://readthedocs.org/api/v2/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;the list of projects available in the public Read The Docs API&lt;/a&gt;, and has its limitations. In particular, spam, inactive, or abandoned projects are not filtered.&lt;/p&gt;
&lt;h2 id=&#34;totals&#34;&gt;Totals
&lt;/h2&gt;&lt;p&gt;This data is current as of May 20, 2018. At that time, there were 90,129 total projects on &lt;code&gt;readthedocs.io&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Starting out, I had assumed that the majority of projects had all four of these attributes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hosted in Git&lt;/li&gt;
&lt;li&gt;Programmed in Python&lt;/li&gt;
&lt;li&gt;Documented in English&lt;/li&gt;
&lt;li&gt;Documentation generated with Sphinx&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As it turned out, this particular combination is only used on 35.8% (32,218) of projects, so let&amp;rsquo;s take a look at how each of these vary.&lt;/p&gt;
&lt;h2 id=&#34;programming-languages&#34;&gt;Programming languages
&lt;/h2&gt;&lt;p&gt;The two main conclusions I drew by looking at the programming languages are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Python is the largest developer community that is using the Read the Docs platform&lt;/li&gt;
&lt;li&gt;A lot of projects are hosting documentation that is not tagged with a programming language&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;#&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;%&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;Projects&lt;/th&gt;
          &lt;th&gt;Programming language&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;1&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;39.92%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;35978&lt;/td&gt;
          &lt;td&gt;Not code (“just words”)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;39.27%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;35391&lt;/td&gt;
          &lt;td&gt;Python&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;9.27%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;8354&lt;/td&gt;
          &lt;td&gt;(No language listed)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;4&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2.83%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2551&lt;/td&gt;
          &lt;td&gt;Javascript&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;5&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2.29%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2060&lt;/td&gt;
          &lt;td&gt;PHP&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;6&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;1.15%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;1040&lt;/td&gt;
          &lt;td&gt;C++&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;7&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;1.13%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;1018&lt;/td&gt;
          &lt;td&gt;Java&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;8&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.85%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;769&lt;/td&gt;
          &lt;td&gt;Other&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;9&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.77%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;690&lt;/td&gt;
          &lt;td&gt;C#&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;10&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.71%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;640&lt;/td&gt;
          &lt;td&gt;C&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;11&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.42%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;380&lt;/td&gt;
          &lt;td&gt;CSS&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;12&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.34%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;304&lt;/td&gt;
          &lt;td&gt;Go&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;13&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.31%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;283&lt;/td&gt;
          &lt;td&gt;Ruby&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;14&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.31%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;277&lt;/td&gt;
          &lt;td&gt;Julia&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;15&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.11%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;96&lt;/td&gt;
          &lt;td&gt;Perl&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;16&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.06%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;55&lt;/td&gt;
          &lt;td&gt;Objective C&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;17&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.06%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;54&lt;/td&gt;
          &lt;td&gt;R&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;18&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.04%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;36&lt;/td&gt;
          &lt;td&gt;TypeScript&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;19&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.03%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;31&lt;/td&gt;
          &lt;td&gt;Scala&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;20&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.03%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;30&lt;/td&gt;
          &lt;td&gt;Haskell&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;21&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.03%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;29&lt;/td&gt;
          &lt;td&gt;Lua&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;22&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.02%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;22&lt;/td&gt;
          &lt;td&gt;Swift&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;23&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.02%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;15&lt;/td&gt;
          &lt;td&gt;CoffeeScript&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;24&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.02%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;14&lt;/td&gt;
          &lt;td&gt;Visual Basic&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;25&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.01%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;12&lt;/td&gt;
          &lt;td&gt;Groovy&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;documentation-languages&#34;&gt;Documentation languages
&lt;/h2&gt;&lt;p&gt;You might have guessed that English dominates in software documentation, but here is the data:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;#&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;%&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;Projects&lt;/th&gt;
          &lt;th&gt;Language&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;1&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;93.1%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;83888&lt;/td&gt;
          &lt;td&gt;English (en)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2.4%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2178&lt;/td&gt;
          &lt;td&gt;Indonesian (id)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;1.4%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;1287&lt;/td&gt;
          &lt;td&gt;Chinese (zh, zh_TW, zh_CN)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;4&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.5%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;456&lt;/td&gt;
          &lt;td&gt;Russian (ru)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;5&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.5%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;425&lt;/td&gt;
          &lt;td&gt;Spanish (es)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;6&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.5%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;412&lt;/td&gt;
          &lt;td&gt;French (fr)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;7&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.3%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;254&lt;/td&gt;
          &lt;td&gt;Portuguese (pt)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;8&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.3%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;233&lt;/td&gt;
          &lt;td&gt;German (de)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;9&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.2%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;209&lt;/td&gt;
          &lt;td&gt;Italian (it)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;10&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.2%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;208&lt;/td&gt;
          &lt;td&gt;Japanese (jp)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;-&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.6%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;579&lt;/td&gt;
          &lt;td&gt;All other languages&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;In total, documentation on Read the Docs has been published in 54 languages. The &amp;ldquo;All other languages&amp;rdquo; item here represents 44 other languages.&lt;/p&gt;
&lt;h2 id=&#34;documentation-build-tool&#34;&gt;Documentation build tool
&lt;/h2&gt;&lt;p&gt;The majority are using the Sphinx documentation generator. The table here counts &lt;code&gt;sphinx&lt;/code&gt;, &lt;code&gt;sphinx_htmldir&lt;/code&gt; and &lt;code&gt;sphinx_singlehtml&lt;/code&gt; together.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;#&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;%&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;Projects&lt;/th&gt;
          &lt;th&gt;Language&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;1&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;92.5%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;83364&lt;/td&gt;
          &lt;td&gt;Sphinx&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;6.9%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;6229&lt;/td&gt;
          &lt;td&gt;MkDocs&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.6%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;536&lt;/td&gt;
          &lt;td&gt;Auto-select&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;version-control&#34;&gt;Version control
&lt;/h2&gt;&lt;p&gt;Git is the version control system used for the vast majority of projects.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;#&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;%&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;Projects&lt;/th&gt;
          &lt;th&gt;Version control&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;1&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;96.5%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;86988&lt;/td&gt;
          &lt;td&gt;Git&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2.1%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;1879&lt;/td&gt;
          &lt;td&gt;Mercurial&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.9%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;816&lt;/td&gt;
          &lt;td&gt;SVN&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;4&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;0.5%&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;446&lt;/td&gt;
          &lt;td&gt;Bazaar&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
</description>
        </item>
        <item>
        <title>Recovering text from a receipt with escpos-tools</title>
        <link>https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools</link>
        <pubDate>Thu, 17 May 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools</guid>
        <description>&lt;p&gt;I have written previously about how to generate receipts for printers which understand ESC/POS. Today, I thought I would write about the opposite process.&lt;/p&gt;
&lt;p&gt;Unlike &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/PostScript&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;PostScript&lt;/a&gt;, the ESC/POS binary language is not commonly understood by software. I wrote a few utilities last year to help change that, called &lt;a class=&#34;link&#34; href=&#34;https://github.com/receipt-print-hq/escpos-tools&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;escpos-tools&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In this post, I&amp;rsquo;ll step through an example ESC/POS binary file that an &lt;code&gt;escpos-tools&lt;/code&gt; user sent to me, and show how we can turn it back into a usable format. The tools we are using are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/receipt-print-hq/escpos-tools&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;escpos-tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.imagemagick.org/script/index.php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;ImageMagick&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/tesseract-ocr/tesseract&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;tesseract&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You might need this sort of process if you need to email a copy of your receipts, or to archive them for audit use.&lt;/p&gt;
&lt;h2 id=&#34;printing-the-file&#34;&gt;Printing the file
&lt;/h2&gt;&lt;p&gt;Binary print files are generated from drivers. I can feed this one back to my printer like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat receipt.bin &amp;gt; /dev/usb/lp0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;My Epson TM-T20 receipt printer understands ESC/POS, and prints this out:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/2018-05-receipt-printed.png&#34;
	width=&#34;1024&#34;
	height=&#34;708&#34;
	srcset=&#34;https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/2018-05-receipt-printed_hu_e67ebb055d4ec0db.png 480w, https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/2018-05-receipt-printed_hu_191a6a1d50f872ce.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;144&#34;
		data-flex-basis=&#34;347px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;installing-escpos-tools&#34;&gt;Installing escpos-tools
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;escpos-tools&lt;/code&gt; is not packaged yet, so you need &lt;code&gt;git&lt;/code&gt; and &lt;code&gt;composer&lt;/code&gt; (from the PHP eco-system) to use it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ git clone https://github.com/receipt-print-hq/escpos-tools
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ &lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; escpos-tools
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ composer install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;inspecting-the-file&#34;&gt;Inspecting the file
&lt;/h2&gt;&lt;p&gt;There is text in the file, so the first thing you should try to do is &lt;code&gt;esc2text&lt;/code&gt;. In this case, which works like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ php esc2text.php receipt.bin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this case, I got no output, so I switch to &lt;code&gt;-v&lt;/code&gt; to show the commands being found.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ php esc2text.php receipt.bin  -v
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;DEBUG&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; SetRelativeVerticalPrintPositionCmd 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;DEBUG&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; GraphicsDataCmd 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;DEBUG&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; GraphicsDataCmd 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;DEBUG&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; SetRelativeVerticalPrintPositionCmd 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This indicates that there is no text being sent to the receipt, only images. We know from the print-out that the images contain text, so we need a few more utilities.&lt;/p&gt;
&lt;h2 id=&#34;recovering-images-from-the-receipt&#34;&gt;Recovering images from the receipt
&lt;/h2&gt;&lt;p&gt;To extract the images, use &lt;code&gt;escimages&lt;/code&gt;. It runs like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ php escimages.php --file receipt.bin
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; Image 1: 576x56 &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; Image 2: 576x56 &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; Image 3: 576x56 &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; Image 4: 576x56 &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; Image 5: 576x56 &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; Image 6: 576x56 &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; Image 7: 576x56 &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; Image 8: 576x52 &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This gave me 8 narrow images:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-01.png&#34;
	width=&#34;576&#34;
	height=&#34;56&#34;
	srcset=&#34;https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-01_hu_ed39967ab1e9bf40.png 480w, https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-01_hu_1d281f52ac7b1329.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;1028&#34;
		data-flex-basis=&#34;2468px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-02.png&#34;
	width=&#34;576&#34;
	height=&#34;56&#34;
	srcset=&#34;https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-02_hu_536e917cba75f8d0.png 480w, https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-02_hu_fe00d9deb5a4910.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;1028&#34;
		data-flex-basis=&#34;2468px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-03.png&#34;
	width=&#34;576&#34;
	height=&#34;56&#34;
	srcset=&#34;https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-03_hu_b7258ede33a4dd4b.png 480w, https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-03_hu_f35c7fa505b39dc.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;1028&#34;
		data-flex-basis=&#34;2468px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-04.png&#34;
	width=&#34;576&#34;
	height=&#34;56&#34;
	srcset=&#34;https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-04_hu_d0204fb9f84a3522.png 480w, https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-04_hu_ca430b8978182be0.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;1028&#34;
		data-flex-basis=&#34;2468px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-05.png&#34;
	width=&#34;576&#34;
	height=&#34;56&#34;
	srcset=&#34;https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-05_hu_4052ea2e8af39b9a.png 480w, https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-05_hu_d361c61cbf961e2a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;1028&#34;
		data-flex-basis=&#34;2468px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-06.png&#34;
	width=&#34;576&#34;
	height=&#34;56&#34;
	srcset=&#34;https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-06_hu_17b5e0f013677705.png 480w, https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-06_hu_babaf9111285721e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;1028&#34;
		data-flex-basis=&#34;2468px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-07.png&#34;
	width=&#34;576&#34;
	height=&#34;56&#34;
	srcset=&#34;https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-07_hu_7fc716e56c029ed5.png 480w, https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-07_hu_95d378a0185c9216.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;1028&#34;
		data-flex-basis=&#34;2468px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-08.png&#34;
	width=&#34;576&#34;
	height=&#34;52&#34;
	srcset=&#34;https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-08_hu_6b4d271e15ace2ef.png 480w, https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/receipt-08_hu_d9ecbb1ba6980db1.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;1107&#34;
		data-flex-basis=&#34;2658px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Using ImageMagick&amp;rsquo;s &lt;code&gt;convert&lt;/code&gt; command, these can be combined into one image like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;convert -append receipt-*.png -density 70 -units PixelsPerInch receipt.png
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The result is now the same as what the printer produces, but in crisp digital form:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/2018-05-receipt-joined.png&#34;
	width=&#34;576&#34;
	height=&#34;444&#34;
	srcset=&#34;https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/2018-05-receipt-joined_hu_c1e43fd4ccdf1f48.png 480w, https://mike42.me/blog/2018-05-recovering-text-from-a-receipt-with-escpos-tools/2018-05-receipt-joined_hu_65a29b4a5e03884f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;129&#34;
		data-flex-basis=&#34;311px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;recovering-text-from-the-receipt&#34;&gt;Recovering text from the receipt
&lt;/h2&gt;&lt;p&gt;Lastly, &lt;code&gt;tesseract&lt;/code&gt; is an open source OCR engine which can recover text from images. This image is a lossless copy of what we sent to the printer, which is an &amp;ldquo;easy&amp;rdquo; input for OCR.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ tesseract receipt.png -
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Estimating resolution as 279
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Test Receipt for USB Printer 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Mar 17, 2018
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;10:12 PM
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Ticket: 01
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Item $0,00
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Total $0.00
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This quality of output is fairly accurate for an untrained OCR engine.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;The &lt;code&gt;escpos-tools&lt;/code&gt; family of utilities gives some visibility into the contents of ESC/POS binary files.&lt;/p&gt;
&lt;p&gt;If you have a use case which requires working with this type of file, then I would encourage you to consider contributing code or example files to the project, so that the utilities can be improved over time.&lt;/p&gt;
&lt;p&gt;The project is hosted on GitHub at &lt;a class=&#34;link&#34; href=&#34;https://github.com/receipt-print-hq/escpos-tools&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;receipt-print-hq/escpos-tools&lt;/a&gt;.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>First impressions of the Rust programming language</title>
        <link>https://mike42.me/blog/2018-05-first-impressions-of-rust</link>
        <pubDate>Thu, 10 May 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-05-first-impressions-of-rust</guid>
        <description>&lt;p&gt;I needed to write a small command-line utility recently, and thought that it would be a good chance to finally try out the Rust programming language.&lt;/p&gt;
&lt;p&gt;I was hoping to learn the basics and implement this program in a few hours, but I found that it wasn&amp;rsquo;t trivial to just pick up Rust and start writing programs immediately. The compiler is quite strict about how you use variables, so progress is slow if you don&amp;rsquo;t really know what you are doing. Still, Rust allows you to produce programs with some valuable properties, so I&amp;rsquo;m planning to set aside some time to learn it properly.&lt;/p&gt;
&lt;p&gt;In the meantime, these are a few of the first impressions that I had of Rust, as somebody completely new to this particular software ecosystem.&lt;/p&gt;
&lt;h2 id=&#34;initial-installation-is-easy&#34;&gt;Initial installation is easy
&lt;/h2&gt;&lt;p&gt;I needed to install the &lt;code&gt;rustc&lt;/code&gt; compiler and &lt;code&gt;cargo&lt;/code&gt; dependency manager. I found that the command packages for Debian testing were up-to-date, so I installed directly from &lt;code&gt;apt&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install rustc cargo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;From there, it took all of one minute to create a file called &lt;code&gt;hello.rs&lt;/code&gt;, drop the &amp;ldquo;Hello world&amp;rdquo; program, and see it run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;fn&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;println!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Hello&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;rustc&lt;/code&gt; compiler has a simple-enough invocation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ rustc hello.rs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the resulting program ran as expected.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ./hello 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Hello
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There were no surprises here. It seemed to work just like C so-far.&lt;/p&gt;
&lt;h2 id=&#34;output-files-are-large&#34;&gt;Output files are large
&lt;/h2&gt;&lt;p&gt;The output binary file was much larger than I expected, at 246K.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ls -Ahl hello
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-rwxr-xr-x 1 mike mike 246K Apr 13 21:55 hello
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For comparison, I wrote out a similar program in C to see how large it was.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Hello&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It compiles and runs with the below commands, was 8K.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ gcc hello.c -o hello
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ./hello 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Hello
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ls -Ahl hello
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-rwxr-xr-x 1 mike mike 8.3K Apr 13 21:57 hello
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;a class=&#34;link&#34; href=&#34;https://www.rust-lang.org/en-US/faq.html#why-do-rust-programs-have-larger-binary-sizes-than-C-programs&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;FAQ&lt;/a&gt; explained a few specific reasons why this was the case.&lt;/p&gt;
&lt;h2 id=&#34;compile-is-slow&#34;&gt;Compile is slow
&lt;/h2&gt;&lt;p&gt;Compilation took around a quarter of a second. This does not seem like much, but it certainty slower than I expected for such trivial code.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ time rustc hello.rs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;real	0m0.298s
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Compared with the C program:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ time gcc hello.c -o hello
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;real	0m0.044s
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Again, the &lt;a class=&#34;link&#34; href=&#34;https://www.rust-lang.org/en-US/faq.html#why-is-rustc-slow&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;FAQ&lt;/a&gt; points out that zero-cost abstractions incur a compile-time penalty.&lt;/p&gt;
&lt;p&gt;Since compilation &lt;a class=&#34;link&#34; href=&#34;https://xkcd.com/303/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;is a notoriously time-consuming activity&lt;/a&gt; with existing languages, I&amp;rsquo;m hoping that the compile times for Rust are acceptable for small projects.&lt;/p&gt;
&lt;h2 id=&#34;legendary-compile-errors&#34;&gt;Legendary compile errors
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;ve read about &lt;code&gt;rustc&lt;/code&gt; being very strict, but printing good errors. So, I deleted a &lt;code&gt;!&lt;/code&gt; character and tried to re-compile.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;fn&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Hello&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code produced an error as expected.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-mysql&#34; data-lang=&#34;mysql&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rustc&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hello&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rs&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;E0423&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;expected&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;found&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;macro&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;println&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;--&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hello&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;^^^^^^^&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;did&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;you&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mean&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;println&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(...)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;`?&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;aborting&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;due&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;to&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;previous&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The error message suggested the correct code to use, which is better than what you get from most compilers. I&amp;rsquo;m pretty happy with that.&lt;/p&gt;
&lt;h2 id=&#34;editor-support-is-good&#34;&gt;Editor support is good
&lt;/h2&gt;&lt;p&gt;Next, I needed a better Rust editor. Eclipse support for Rust was present, but had a patchy maintenance status.&lt;/p&gt;
&lt;p&gt;So I tried adding the Rust plugin for IntelliJ IDEA community edition, which is still a fully open source stack. This was point-and-click. The basic steps follow-&lt;/p&gt;
&lt;p&gt;Open IntelliJ and click &lt;strong&gt;Configure&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-05-first-impressions-of-rust/2018-05-intellij-rust-01.png&#34;
	width=&#34;1166&#34;
	height=&#34;879&#34;
	srcset=&#34;https://mike42.me/blog/2018-05-first-impressions-of-rust/2018-05-intellij-rust-01_hu_c3940655078d4141.png 480w, https://mike42.me/blog/2018-05-first-impressions-of-rust/2018-05-intellij-rust-01_hu_27128993bc0863de.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;132&#34;
		data-flex-basis=&#34;318px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Then &lt;strong&gt;Plugins&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-05-first-impressions-of-rust/2018-05-intellij-rust-02.png&#34;
	width=&#34;452&#34;
	height=&#34;516&#34;
	srcset=&#34;https://mike42.me/blog/2018-05-first-impressions-of-rust/2018-05-intellij-rust-02_hu_e4dbb171de0f73ec.png 480w, https://mike42.me/blog/2018-05-first-impressions-of-rust/2018-05-intellij-rust-02_hu_6716520a70da1dfe.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;87&#34;
		data-flex-basis=&#34;210px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Search for &amp;ldquo;rust&amp;rdquo;, and click &lt;strong&gt;Search in Repositories&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-05-first-impressions-of-rust/2018-05-intellij-rust-04.png&#34;
	width=&#34;2170&#34;
	height=&#34;1186&#34;
	srcset=&#34;https://mike42.me/blog/2018-05-first-impressions-of-rust/2018-05-intellij-rust-04_hu_a269c4d0f17bb2b6.png 480w, https://mike42.me/blog/2018-05-first-impressions-of-rust/2018-05-intellij-rust-04_hu_7facffe3025c5562.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;182&#34;
		data-flex-basis=&#34;439px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Then click &lt;strong&gt;Rust&lt;/strong&gt; → &lt;strong&gt;Install&lt;/strong&gt;, and wait:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-05-first-impressions-of-rust/2018-05-intellij-rust-05.png&#34;
	width=&#34;1007&#34;
	height=&#34;178&#34;
	srcset=&#34;https://mike42.me/blog/2018-05-first-impressions-of-rust/2018-05-intellij-rust-05_hu_685d973b5cb0c326.png 480w, https://mike42.me/blog/2018-05-first-impressions-of-rust/2018-05-intellij-rust-05_hu_9efa2300f2c4f70c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;565&#34;
		data-flex-basis=&#34;1357px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Once it installs, restart the IDE.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-05-first-impressions-of-rust/2018-05-rust-06.png&#34;
	width=&#34;2170&#34;
	height=&#34;1186&#34;
	srcset=&#34;https://mike42.me/blog/2018-05-first-impressions-of-rust/2018-05-rust-06_hu_2235f1a7867ba6e0.png 480w, https://mike42.me/blog/2018-05-first-impressions-of-rust/2018-05-rust-06_hu_4d33823954279591.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;182&#34;
		data-flex-basis=&#34;439px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;New Project&lt;/strong&gt; dialog now shows Rust as an option.&lt;/p&gt;
&lt;p&gt;I needed the &lt;code&gt;rust-src&lt;/code&gt; package to fill out these options:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo apt-get install rust-src
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ apt-file list rust-src
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/usr/src/rustc-1.24.1/src/ ..
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the IntelliJ Rust environment, most editor features worked, but the debugger was not supported.&lt;/p&gt;
&lt;p&gt;So, IDE support is mostly there, but it&amp;rsquo;s not easy to start hacking as something like Java.&lt;/p&gt;
&lt;h2 id=&#34;dependency-management&#34;&gt;Dependency management
&lt;/h2&gt;&lt;p&gt;I noticed that Cargo produces &lt;code&gt;.lock&lt;/code&gt; files which contain checksums and exact versions of dependencies.&lt;/p&gt;
&lt;p&gt;As a &lt;code&gt;composer&lt;/code&gt; and &lt;code&gt;yarn&lt;/code&gt; user, this was familiar.&lt;/p&gt;
&lt;h2 id=&#34;clippy&#34;&gt;&amp;ldquo;Clippy&amp;rdquo;
&lt;/h2&gt;&lt;p&gt;I couldn&amp;rsquo;t use the clippy linter to check my code, because it does not work on the stable Rust releases. The &amp;rsquo;nightly&amp;rsquo; Rust releases are not available in the Debian archive.&lt;/p&gt;
&lt;p&gt;So, for installing &lt;code&gt;rustc&lt;/code&gt;, I should have used &lt;code&gt;rustup&lt;/code&gt;, not &lt;code&gt;apt-get&lt;/code&gt;. Lesson learned!&lt;/p&gt;
&lt;h2 id=&#34;documentation&#34;&gt;Documentation
&lt;/h2&gt;&lt;p&gt;I followed the &amp;ldquo;Guessing game tutorial&amp;rdquo; from the official Rust book in the IDE, which taught basic I/O, variable scope and control structures in Rust.&lt;/p&gt;
&lt;p&gt;The go-to source reference for Rust is &amp;lsquo;The Rust Book&amp;rsquo;, which is also collaboratively built and freely licensed.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://doc.rust-lang.org/book/second-edition/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;The Rust Programming Language (Second Edition)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is also an immense amount of high-quality discussion taking place between Rust users, which I found to be surprisingly accessible as a novice.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/ctjhoa/rust-learning&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;ctjhoa/rust-learning&lt;/a&gt; on github.com&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://stackoverflow.com/questions/tagged/rust&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Questions tagged &amp;lsquo;rust&amp;rsquo;&lt;/a&gt; on stackoverflow.com&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Having never used the language before, I didn&amp;rsquo;t have to ask any questions to get these basics working, which suggests that the available resources are pretty good.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to print the characters in an ESC/POS printer code page</title>
        <link>https://mike42.me/blog/2018-05-how-to-print-the-characters-in-an-esc-pos-printer-code-page</link>
        <pubDate>Thu, 03 May 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-05-how-to-print-the-characters-in-an-esc-pos-printer-code-page</guid>
        <description>&lt;p&gt;I&amp;rsquo;ve been working on software that interacts with ESC/POS receipt printers for some time, and a constant source of trouble is the archaic &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Character_encoding&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;character encoding&lt;/a&gt; scheme used on these printers.&lt;/p&gt;
&lt;p&gt;Most commonly, non-ASCII characters are accessed by swapping the extended range to a different 128-character code page. The main open source drivers (&lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;escpos-php&lt;/a&gt; and &lt;a class=&#34;link&#34; href=&#34;https://github.com/python-escpos/python-escpos&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;python-escpos&lt;/a&gt;) are both capable of auto-selecting an encoding, but they need a good database of known encodings to power this feature for each individual printer.&lt;/p&gt;
&lt;p&gt;Today, I&amp;rsquo;ll share a small utility that can print out the contents of a code page, like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-05-how-to-print-the-characters-in-an-esc-pos-printer-code-page/2018-05-code-page-1-1.png&#34;
	width=&#34;1024&#34;
	height=&#34;443&#34;
	srcset=&#34;https://mike42.me/blog/2018-05-how-to-print-the-characters-in-an-esc-pos-printer-code-page/2018-05-code-page-1-1_hu_6459b0dfe9e8e87b.png 480w, https://mike42.me/blog/2018-05-how-to-print-the-characters-in-an-esc-pos-printer-code-page/2018-05-code-page-1-1_hu_a096ccc1ba4d4989.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;231&#34;
		data-flex-basis=&#34;554px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;A printer&amp;rsquo;s documentation vaguely labeled this encoding as &amp;ldquo;[1] Katakana&amp;rdquo;. By printing it out, I can see that if I map &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Code_page_932_%28IBM%29&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;single-byte half-width Katakana from Code Page 932&lt;/a&gt;, it will appear correctly in this code page. That&amp;rsquo;s type of information you need when you&amp;rsquo;re asked about it on an issue tracker!&lt;/p&gt;
&lt;h2 id=&#34;usage&#34;&gt;Usage
&lt;/h2&gt;&lt;p&gt;You will generally find a list of code pages with a corresponding number for each one (0-255) in an ESC/POS printer&amp;rsquo;s documentation.&lt;/p&gt;
&lt;p&gt;This command-line tool then takes a list of code pages to inspect, and will output raw binary that generates a table like the one above when sent to the printer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;php escpos-caracter-table.php NUMBER ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So to print the code pages 1, 2 and 3 to a binary file, the command would be:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;php escpos-character-tables.php &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; &amp;gt; code-page-1.bin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, you need to know how to do raw printing. Raw USB printing on Linux typically works like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat code-page-1.bin &amp;gt; /dev/usb/lp0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For other platforms, it will be different! You will need to do a bit of research on raw printing for your platform if you haven&amp;rsquo;t tried it before.&lt;/p&gt;
&lt;h2 id=&#34;the-code-escpos-character-tablesphp&#34;&gt;The code: escpos-character-tables.php
&lt;/h2&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * This standalone script can be used to print the contents of a code page
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * for troubleshooting.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * Usage: php escpos-caracter-table.php NUMBER ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * Code pages are numbered 0-255.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * The ESC/POS binary will be send to stdout, and should be redirected to a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * file or printer:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; *   php escpos-caracter-table.php 20 &amp;gt; /dev/usb/lp0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * @author Michael Billington &amp;lt; michael.billington@gmail.com &amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * @license MIT
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Sanity check */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php_sapi_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;cli&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;die&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;This is a command-line script, invoke via php.exen&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;die&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;At least one code page number must be specifiedn&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;array_shift&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;foreach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$argv&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$codePage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;is_numeric&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$codePage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$codePage&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$codePage&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;255&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;die&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Code pages must be numbered 0-255&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Reset */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$str&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x1b&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;@&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;foreach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$argv&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$codePage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Print header, switch code page */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$str&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x1b&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;t&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$codePage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$str&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x1b&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;E&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x01&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;Code page &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$codePage\x1bE\x00\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$str&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x1b&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;E&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x01&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;  0123456789ABCDEF0123456789ABCDEF&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x1b&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;E&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x00\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$chars&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_repeat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;128&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;128&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$chars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;128&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$y&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$row&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$rowHeader&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x1b&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;E&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x01&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;strtoupper&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;dechex&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x1b&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;E&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x00&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$row&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;substr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$chars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$str&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$rowHeader&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$row\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Cut */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$str&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x1d&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;V&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x41\x03&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Output to STDOUT */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;file_put_contents&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;php://stdout&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>Optimization: How I made my PHP code run 100 times faster</title>
        <link>https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster</link>
        <pubDate>Thu, 26 Apr 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster</guid>
        <description>&lt;p&gt;I&amp;rsquo;ve had a &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/wikitext&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;PHP wikitext parser&lt;/a&gt; as a dependency of some of my projects since 2012. It has always been a minor performance bottleneck, and I recently decided to do something about it.&lt;/p&gt;
&lt;p&gt;I prepared &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/wikitext/pull/14&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;an update to the code&lt;/a&gt; over the course of a month, and achieved a &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Speedup&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;speedup&lt;/a&gt; of 142 times over the original implementation.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster/2018-02-runtime.png&#34;
	width=&#34;640&#34;
	height=&#34;480&#34;
	srcset=&#34;https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster/2018-02-runtime_hu_aa9684da65d2edfa.png 480w, https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster/2018-02-runtime_hu_ccd579739f9f76c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Before: 20.65 seconds, After: 0.145 seconds&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;A lot of the information that I could find online about PHP performance was very outdated, so I decided to write a bit about what I&amp;rsquo;ve learned. This post walks through the process I used, and the things which were were slowing down my code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This is a long read&lt;/strong&gt; &amp;ndash; I&amp;rsquo;ve included examples which show slow code, and what I replaced them with. If you&amp;rsquo;re a serious PHP programmer, then read on!&lt;/p&gt;
&lt;h2 id=&#34;lesson-1-know-when-to-optimize&#34;&gt;Lesson 1: Know when to optimize
&lt;/h2&gt;&lt;p&gt;Conventional wisdom seems to dictate that making your code faster is a waste of developer time.&lt;/p&gt;
&lt;p&gt;I think it makes you a better programmer to occasionally optimize something in a language that you normally work with. Having a well-calibrated intuition about how your code will run is part of becoming proficient in a language, and you will tend to create fewer performance problems if you&amp;rsquo;ve got that intuition.&lt;/p&gt;
&lt;p&gt;But you do need to be selective about it. This code has survived in the wild for over five years, and I think I will still be using it in another five. This code is also a good candidate because it does not access external resources, so there is only one component to examine.&lt;/p&gt;
&lt;h2 id=&#34;lesson-2-write-tests&#34;&gt;Lesson 2: Write tests
&lt;/h2&gt;&lt;p&gt;In the spirit of &lt;a class=&#34;link&#34; href=&#34;http://wiki.c2.com/?MakeItWorkMakeItRightMakeItFast&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;MakeItWorkMakeItRightMakeItFast&lt;/a&gt;, I started by checking my test suite so that I could refactor the code with confidence.&lt;/p&gt;
&lt;p&gt;In my case, I haven&amp;rsquo;t got good unit tests, but I have input files that I can feed through the parser to compare with known-good HTML output, which serves the same purpose:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;php example.php &amp;gt; out.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;diff good.txt out.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I ran this after every change to the code, so that I could be sure that the changes were not affecting the output.&lt;/p&gt;
&lt;h2 id=&#34;lesson-3-profile-your-code--question-your-assumptions&#34;&gt;Lesson 3: Profile your code &amp;amp; Question your assumptions
&lt;/h2&gt;&lt;p&gt;Code profiling allows you see how each part of your program is contributing to its overall run-time. This helps you to target your optimization efforts.&lt;/p&gt;
&lt;p&gt;The two main debuggers for PHP are Zend and Xdebug, which can both profile your code. I have &lt;code&gt;xdebug&lt;/code&gt; installed, which is the free debugger, and I use the Eclipse IDE, which is the free IDE. Unfortunately, the built-in profiling tool in Eclipse seems to only support the Zend debugger, so I have to profile my scripts on the command-line.&lt;/p&gt;
&lt;p&gt;The best sources of information for this are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://xdebug.org/docs/profiler&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Xdebug2: Profiling PHP Scripts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://stackoverflow.com/questions/2729086/how-do-i-set-up-php-profiling-on-eclipse&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;StackOverflow: How do I set up PHP profiling on Eclipse?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On Debian or Ubuntu, &lt;code&gt;xdebug&lt;/code&gt; is installed via &lt;code&gt;apt-get&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install php-cli php-xdebug
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On Fedora, the package is called &lt;code&gt;php-pecl-xdebug&lt;/code&gt;, and is installed as:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo dnf install php-pecl-xdebug
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, I executed a slow-running example script with profiling enabled:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;php -dxdebug.profiler_enable&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; -dxdebug.profiler_output_dir&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;. example.php
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This produces a profile file, which you can use any valgrind-compatible tools to inspect. I used &lt;code&gt;kcachegrind&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install kcachegrind
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And for fedora:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo dnf install kcachegrind
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can locate and open the profile on the command-line like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ls
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kcachegrind cachegrind.out.13385
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Before profiling, I had guessed that the best way to speed up the code would be to reduce the amount of string concatenation. I have lots of tight loops which append characters one-at-a-time:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$buffer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$c&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Xdebug showed me that my guess was wrong, and I would have wasted a lot of time if I tried to remove string concatenation.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster/2018-03-kcachegrind-php-1.png&#34;
	width=&#34;3180&#34;
	height=&#34;1770&#34;
	srcset=&#34;https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster/2018-03-kcachegrind-php-1_hu_37f7504391cf6a75.png 480w, https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster/2018-03-kcachegrind-php-1_hu_69435e5427f8f4b2.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;179&#34;
		data-flex-basis=&#34;431px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Instead, it was clear that I was&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Calculating the same thing hundreds of times over.&lt;/li&gt;
&lt;li&gt;Doing it inefficiently.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;lesson-4-avoid-multibyte-string-functions&#34;&gt;Lesson 4: Avoid multibyte string functions
&lt;/h2&gt;&lt;p&gt;I had used functions from the &lt;code&gt;mbstring&lt;/code&gt; extension (&lt;code&gt;mb_strlen&lt;/code&gt;, &lt;code&gt;mb_substr&lt;/code&gt;) to replace &lt;code&gt;strlen&lt;/code&gt; and &lt;code&gt;substr&lt;/code&gt; throughout my code. This is the simplest way to add UTF-8 support when iterating strings, &lt;a class=&#34;link&#34; href=&#34;https://stackoverflow.com/questions/885241/php-string-indexing&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;is commonly suggested&lt;/a&gt;, and is a bad idea.&lt;/p&gt;
&lt;h3 id=&#34;what-developers-do&#34;&gt;What developers do
&lt;/h3&gt;&lt;p&gt;If you have an ASCII string in PHP and want to iterate over each byte, the idiomatic way to do it is with a &lt;code&gt;for&lt;/code&gt; loop which indexes into the string, something like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Make a test string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testString&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_repeat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;60000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Loop through test string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;strlen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;substr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// Do work on $c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ve used &lt;code&gt;substr&lt;/code&gt; here so that I can show that it has the same usage as &lt;code&gt;mb_substr&lt;/code&gt;, which &lt;a class=&#34;link&#34; href=&#34;http://php.net/manual/en/function.mb-internal-encoding.php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;generally&lt;/a&gt; operates on UTF-8 characters. The idiomatic PHP for iterating over a multibyte string one character at a time would be:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Make a test string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testString&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_repeat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;60000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Loop through test string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;mb_strlen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;mb_substr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// Do work on $c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since &lt;code&gt;mb_substr&lt;/code&gt; needs to parse UTF-8 from the start of the string each time it is called, the second snippet runs in &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Time_complexity&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;polynomial time&lt;/a&gt;, where the snippet that calls &lt;code&gt;substr&lt;/code&gt; in a loop is linear.&lt;/p&gt;
&lt;p&gt;With a few kilobytes of input, this makes &lt;code&gt;mb_substr&lt;/code&gt; unacceptably slow.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster/2018-04-substr-run.png&#34;
	width=&#34;640&#34;
	height=&#34;480&#34;
	srcset=&#34;https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster/2018-04-substr-run_hu_8c23f51b886f6664.png 480w, https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster/2018-04-substr-run_hu_5e7144b18941bc3f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;substr: 0.03 seconds, mb_substr: 4.23 seconds&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;img src=&#34;&#34; alt=&#34;substr: 0.03 seconds, mb_substr: 4.23 seconds&#34; width=&#34;300&#34; height=&#34;225&#34; class=&#34;aligncenter size-medium wp-image-2794&#34; /&gt;
&lt;p&gt;Averaging over 10 runs, the &lt;code&gt;mb_substr&lt;/code&gt; snippet takes 4.23 seconds, while the snippet using &lt;code&gt;substr&lt;/code&gt; takes 0.03 seconds.&lt;/p&gt;
&lt;h3 id=&#34;what-developers-can-do-instead&#34;&gt;What developers can do instead
&lt;/h3&gt;&lt;p&gt;Split your strings into bytes or characters before you iterate, and write methods which operate on arrays rather than strings.&lt;/p&gt;
&lt;p&gt;You can use &lt;code&gt;str_split&lt;/code&gt; to iterate over bytes:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Make a test string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testString&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_repeat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;60000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Loop through test string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testArray&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testArray&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$testArray&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// Do work on $c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And for Unicode strings, use &lt;code&gt;preg_split&lt;/code&gt;. I learned about this trick &lt;a class=&#34;link&#34; href=&#34;https://stackoverflow.com/questions/3666306/how-to-iterate-utf-8-string-in-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;from StackOverflow&lt;/a&gt;, but it might not be the fastest way. Please leave a comment if you have an alternative!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Make a test string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testString&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_repeat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;60000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Loop through test string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testArray&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;preg_split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;//u&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$testString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;PREG_SPLIT_NO_EMPTY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testArray&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$testArray&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// Do work on $c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By converting the string to an array, you can pay the penalty of decoding the UTF-8 up-front. This is a few milliseconds at the start of the script, rather than a few milliseconds each time you need to read a character.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster/2018-04-split-methods.png&#34;
	width=&#34;640&#34;
	height=&#34;480&#34;
	srcset=&#34;https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster/2018-04-split-methods_hu_45d04ad8de951781.png 480w, https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster/2018-04-split-methods_hu_fc3dfe12865919db.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;str_split: 0.0097s, preg_split: 0.0160s&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;After discovering this faster alternative to &lt;code&gt;mb_substr&lt;/code&gt;, I systematically removed every &lt;code&gt;mb_substr&lt;/code&gt; and &lt;code&gt;mb_strlen&lt;/code&gt; from the code I was working on.&lt;/p&gt;
&lt;h2 id=&#34;lesson-5-optimize-for-the-most-common-case&#34;&gt;Lesson 5: Optimize for the most common case
&lt;/h2&gt;&lt;p&gt;Around 50% of the remaining runtime was spent in a method which expanded templates.&lt;/p&gt;
&lt;p&gt;To parse wikitext, you first need to expand templates, which involves detecting tags like &lt;code&gt;{{ template-name | foo=bar }}&lt;/code&gt; and &lt;code&gt;&amp;lt;noinclude&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;My 40 kilobyte test file had fewer than 100 instances of &lt;code&gt;{&lt;/code&gt; and &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;|&lt;/code&gt; and &lt;code&gt;=&lt;/code&gt;, so I added a short-circuit to the code to skip most of the processing, for most of the characters.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$preprocessorChars&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;lt;&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s1&#34;&gt;&amp;#39;=&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s1&#34;&gt;&amp;#39;|&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s1&#34;&gt;&amp;#39;{&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$textChars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;isset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$preprocessorChars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* Fast exit for characters that do not start a tag. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$parsed&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;continue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;c1&#34;&gt;// ... Slower processing 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The slower processing is now avoided 99.75% of the time.&lt;/p&gt;
&lt;p&gt;Checking for the presence of a key in a map is very fast. To illustrate, here are two examples which each branch on &lt;code&gt;{&lt;/code&gt; and &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;|&lt;/code&gt; and &lt;code&gt;=&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This one uses a map to check each character:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Make a test string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testString&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_repeat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;600000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$chars&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;lt;&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s1&#34;&gt;&amp;#39;=&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s1&#34;&gt;&amp;#39;|&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s1&#34;&gt;&amp;#39;{&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Loop through test string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testArray&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;preg_split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;//u&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$testString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;PREG_SPLIT_NO_EMPTY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testArray&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$parsed&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$testArray&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;isset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$chars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$parsed&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;continue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// Never executed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While one uses no map, and has four &lt;code&gt;!==&lt;/code&gt; checks instead:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Make a test string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testString&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_repeat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;600000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Loop through test string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testArray&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;preg_split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;//u&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$testString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;PREG_SPLIT_NO_EMPTY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testArray&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$parsed&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$testArray&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;lt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;=&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;|&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;{&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$parsed&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;continue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// Never executed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Even though the run time of each script includes the generation of a 600kB test string, the difference is still visible:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster/2018-04-map.png&#34;
	width=&#34;640&#34;
	height=&#34;480&#34;
	srcset=&#34;https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster/2018-04-map_hu_967b4a226210e1aa.png 480w, https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster/2018-04-map_hu_9f3191352f10fe07.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;0.29 seconds with map, 0.37 seconds without map&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Averaging over 10 runs, the code took 0.29 seconds when using a map, while it took 0.37 seconds to run the example with used four &lt;code&gt;!==&lt;/code&gt; statements.&lt;/p&gt;
&lt;p&gt;I was a little surprised by this result, but I&amp;rsquo;ll let the data speak for itself rather than try to explain why this is the case.&lt;/p&gt;
&lt;h2 id=&#34;lesson-6-share-data-between-functions&#34;&gt;Lesson 6: Share data between functions
&lt;/h2&gt;&lt;p&gt;The next item to appear in the profiler was the copious use of &lt;code&gt;array_slice&lt;/code&gt;.
My code uses recursive descent, and was constantly slicing up the input to pass around information. The array slicing had replaced earlier string slicing, which was even slower.&lt;/p&gt;
&lt;p&gt;I refactored the code to &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/wikitext/pull/14/commits/ee7aa1852a0cea8fa0d1b473f64fcc3069dd9277&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;pass around the entire string with indices&lt;/a&gt; rather than actually cutting it up.&lt;/p&gt;
&lt;p&gt;As a contrived example, these scripts each use a (very unnecessary) recursive-descent parser to take words from the dictionary and transform them like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;example --&amp;gt; (example!)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first example slices up the input array at each recursion step:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;handleWord&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$word&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;(&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$word&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;!)&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * Parse a word up to the next newline.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;parseWord&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;array&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$textChars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nv&#34;&gt;$parsed&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$textChars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$textChars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;c1&#34;&gt;// Word is finished because we hit a newline
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;      &lt;span class=&#34;nv&#34;&gt;$start&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Past the newline
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;      &lt;span class=&#34;nv&#34;&gt;$remainderChars&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;array_slice&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$textChars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$start&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;parsed&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;handleWord&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$parsed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;remainderChars&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$remainderChars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$parsed&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// Word is finished because we hit the end of the input
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;parsed&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;handleWord&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$parsed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;remainderChars&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * Accept newline-delimited dictionary
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;parseDictionary&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;array&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$textChars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nv&#34;&gt;$parsed&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$textChars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$textChars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;c1&#34;&gt;// Not a word...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;      &lt;span class=&#34;k&#34;&gt;continue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// This is part of a word
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nv&#34;&gt;$start&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$remainderChars&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;array_slice&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$textChars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$result&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;parseWord&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$remainderChars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$textChars&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;remainderChars&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$textChars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$parsed&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;parsed&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;parsed&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$parsed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;remainderChars&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Load file, split into characters, parse, print result
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testString&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;file_get_contents&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;words&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$testArray&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;preg_split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;//u&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$testString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;PREG_SPLIT_NO_EMPTY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;parseDictionary&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testArray&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;file_put_contents&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;words2&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;parsed&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While the second one always takes an index into the input array:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;handleWord&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$word&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;(&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$word&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;!)&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * Parse a word up to the next newline.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;parseWord&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;array&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$textChars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$idxFrom&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nv&#34;&gt;$parsed&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$textChars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$idxFrom&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$textChars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;c1&#34;&gt;// Word is finished because we hit a newline
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;      &lt;span class=&#34;nv&#34;&gt;$start&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Past the newline
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;      &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;parsed&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;handleWord&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$parsed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;remainderIdx&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$parsed&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// Word is finished because we hit the end of the input
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;parsed&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;handleWord&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$parsed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * Accept newline-delimited dictionary
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;parseDictionary&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;array&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$textChars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$idxFrom&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nv&#34;&gt;$parsed&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$textChars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$idxFrom&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$textChars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;c1&#34;&gt;// Not a word...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;      &lt;span class=&#34;k&#34;&gt;continue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// This is part of a word
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nv&#34;&gt;$start&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$result&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;parseWord&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$textChars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;remainderIdx&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$parsed&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;parsed&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;parsed&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$parsed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;remainderChars&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Load file, split into characters, parse, print result
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testString&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;file_get_contents&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;words&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$testArray&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;preg_split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;//u&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$testString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;PREG_SPLIT_NO_EMPTY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;parseDictionary&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testArray&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;file_put_contents&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;words2&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;parsed&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The run-time difference between these examples is again very pronounced:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster/2018-04-slice.png&#34;
	width=&#34;640&#34;
	height=&#34;480&#34;
	srcset=&#34;https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster/2018-04-slice_hu_34d08980cc4e9301.png 480w, https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster/2018-04-slice_hu_4be6e61070d26cf3.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;3.04s with slicing, 0.0302s with no slicing&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Averaging over 10 runs, the code snippet which extracts sub-arrays took 3.04 seconds, while the code that passes around the entire array ran in 0.0302 seconds.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s amazing that such an obvious inefficiency in my code had been hiding behind larger problems before.&lt;/p&gt;
&lt;h2 id=&#34;lesson-7-use-scalar-type-hinting&#34;&gt;Lesson 7: Use scalar type hinting
&lt;/h2&gt;&lt;p&gt;Scalar type hinting looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;foo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;bar&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$baz&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is the secret PHP performance feature that they don&amp;rsquo;t tell you about. It does not actually change the speed of your code, but does ensure that it can&amp;rsquo;t be run on the slower PHP releases before 7.0.&lt;/p&gt;
&lt;p&gt;PHP 7.0 was released in 2015, and it&amp;rsquo;s been established that it is twice as fast as PHP 5.6 in many cases.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;http://php.net/archive/2015.php#id2015-12-03-1&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;News Archive - PHP 7.0.0 Released&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://pantheon.io/blog/php-7-easiest-performance-optimization-i-ever-made&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;PHP 7: The Easiest Performance Optimization I Ever Made&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.phpclasses.org/blog/post/493-php-performance-evolution.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;PHP Performance Evolution&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I think it&amp;rsquo;s reasonable to have a dependency on a supported version of your platform, and performance improvements like this are a good reason to update your minimum supported version of PHP.&lt;/p&gt;
&lt;p&gt;By introducing scalar type hints, you can ensure that your software does not appear to &amp;ldquo;work&amp;rdquo; in a degraded state.&lt;/p&gt;
&lt;p&gt;Simplifying the compatibility landscape will also make performance a more tractable problem.&lt;/p&gt;
&lt;h2 id=&#34;lesson-8-ignore-advice-that-isnt-backed-up-by-relevant-data&#34;&gt;Lesson 8: Ignore advice that isn&amp;rsquo;t backed up by (relevant) data
&lt;/h2&gt;&lt;p&gt;While I was updating this code, I found a lot of out-dated claims about PHP performance, which did not hold true for the versions that I support.&lt;/p&gt;
&lt;p&gt;To call out a few myths that still seem to be alive:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Style of quotes impacts performance.&lt;/li&gt;
&lt;li&gt;Use of by-val is slower than by-ref for variable passing.&lt;/li&gt;
&lt;li&gt;String concatenation is bad for performance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I attempted to implement each of these, and wasted a lot of time. Thankfully, I was measuring the execution time and using version control, so it was easy for me to identify and discard changes which had a negligible or negative performance impact.&lt;/p&gt;
&lt;p&gt;If somebody makes a claim about something being fast or slow in PHP, best assume that it doesn&amp;rsquo;t apply to you, unless you see some example code with timings on a recent PHP version.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;If you&amp;rsquo;ve read this far, then I hope you&amp;rsquo;ve seen that modern PHP is not an intrinsically slow language. A significant speed-up is probably achievable on any real-world code-base with such endemic performance issues.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster/2018-02-runtime.png&#34;
	width=&#34;640&#34;
	height=&#34;480&#34;
	srcset=&#34;https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster/2018-02-runtime_hu_aa9684da65d2edfa.png 480w, https://mike42.me/blog/2018-06-how-i-made-my-php-code-run-100-times-faster/2018-02-runtime_hu_ccd579739f9f76c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Before: 20.65 seconds, After: 0.145 seconds&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;To repeat the graphic from the introduction: the test file could be parsed in 20.65 seconds on the old code, and 0.145 seconds on the improved code (averaging over 10 runs, as before).&lt;/p&gt;
&lt;p&gt;At this point I declared my efforts &amp;ldquo;good enough&amp;rdquo; and moved on. The job is done: although another pass could speed it up further, this code is no longer slow enough to justify the effort.&lt;/p&gt;
&lt;p&gt;Since I&amp;rsquo;ve closed the book on PHP 5, I would be interested in knowing whether there is a faster way to parse UTF-8 with the new &lt;a class=&#34;link&#34; href=&#34;http://php.net/manual/en/class.intlchar.php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;IntlChar&lt;/a&gt; functions, but I&amp;rsquo;ll have to save that for the next project.&lt;/p&gt;
&lt;p&gt;Now that you&amp;rsquo;ve seen some very inefficient ways to write PHP, I also hope that you will be able to avoid introducing similar problems in your own projects!&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Using a receipt printer with the Amazon Echo</title>
        <link>https://mike42.me/blog/2018-04-using-a-receipt-printer-with-the-amazon-echo</link>
        <pubDate>Thu, 19 Apr 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-04-using-a-receipt-printer-with-the-amazon-echo</guid>
        <description>&lt;p&gt;Today, I&amp;rsquo;m sharing this write-up by fellow developer Chris, who used the &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;escpos-php&lt;/a&gt; thermal printing library as part of a setup which printed shopping lists via voice commands, using the Alexa Voice Service API to send the lists back to a Raspberry Pi.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Naturally, the easiest solution [&amp;hellip;] is to print it in thermal paper… Now, combine this with a voice interface, such as ALEXA, and you made yourself a voice controlled list printer.&amp;rdquo;&lt;/p&gt;&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;http://www.mcseven.me/2017/11/amazon-alexa-lists-exercise-putem-on-paper/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Amazon ALEXA Lists Exercise – Put’em on Paper&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I found out about this one through &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/what-is-escpos-and-how-do-i-use-it&#34; &gt;a blog comment&lt;/a&gt;, and it&amp;rsquo;s a recommended read for anybody who is interested in how all of these parts integrate.&lt;/p&gt;
&lt;p&gt;When I first uploaded this printing library four years ago, the Amazon Echo did not exist yet, and I was solving a very specific problem. For an old technology, it&amp;rsquo;s interesting to see that new applications for thermal printers are still appearing, and I&amp;rsquo;m certainly glad to see my software popping up in cool projects like this.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Raster to vector conversion tips</title>
        <link>https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips</link>
        <pubDate>Thu, 12 Apr 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips</guid>
        <description>&lt;p&gt;I have recently been working with some low-resolution bitmap fonts for a few projects, which needed to be re-sized for different uses.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll share here a few tricks that I use to get the detail out of each letter as a vector, so that it can be rendered at a higher resolution.&lt;/p&gt;
&lt;h2 id=&#34;example&#34;&gt;Example
&lt;/h2&gt;&lt;p&gt;A good example might be this picture of a hieroglyph from the &lt;a class=&#34;link&#34; href=&#34;https://www.mediawiki.org/wiki/Extension:WikiHiero&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;WikiHiero MediaWiki extension&lt;/a&gt;, which is 28 pixels wide:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/hiero_A1.png&#34;
	width=&#34;29&#34;
	height=&#34;38&#34;
	srcset=&#34;https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/hiero_A1_hu_f20210ec1f457b8e.png 480w, https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/hiero_A1_hu_7da3085a25aa5c82.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;76&#34;
		data-flex-basis=&#34;183px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Scaled up, it looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/2018-04-hiero_A1_scaled1.png&#34;
	width=&#34;580&#34;
	height=&#34;760&#34;
	srcset=&#34;https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/2018-04-hiero_A1_scaled1_hu_509ab56a0c351006.png 480w, https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/2018-04-hiero_A1_scaled1_hu_723e654b64bcee8.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxxs&#34; 
		data-flex-grow=&#34;76&#34;
		data-flex-basis=&#34;183px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;So small images become very pixelated when you resize them. The good news is that even from a small image, there is quite a lot of detail which we can use. If we&amp;rsquo;re smart about it, the glyph can be rendered like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/2018-04-hiero_A1_scaled2.png&#34;
	width=&#34;580&#34;
	height=&#34;760&#34;
	srcset=&#34;https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/2018-04-hiero_A1_scaled2_hu_66bc3bbabc0e370d.png 480w, https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/2018-04-hiero_A1_scaled2_hu_ad65f748a81ee3ea.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxxs&#34; 
		data-flex-grow=&#34;76&#34;
		data-flex-basis=&#34;183px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;You can still see some artifacts because of the low resolution of the input, but it&amp;rsquo;s clearly an improvement.&lt;/p&gt;
&lt;h2 id=&#34;you-will-need&#34;&gt;You will need
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ImageMagick&lt;/strong&gt; for raster operations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;potrace&lt;/strong&gt; to trace the image.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inkscape&lt;/strong&gt; to produce a high-quality raster.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;steps&#34;&gt;Steps
&lt;/h2&gt;&lt;h3 id=&#34;prepare&#34;&gt;Prepare
&lt;/h3&gt;&lt;p&gt;The tracing program will convert the image to pure black &amp;amp; white as its first step. These transformations make sure that the detail is preserved for tracing.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Padding by 10px on every side to reduce distortion around the edges.&lt;/li&gt;
&lt;li&gt;Scaling by 10x with interpolation&lt;/li&gt;
&lt;li&gt;Convert transparency to white&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;convert hiero_A1.png -bordercolor white -border 10x10 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    -resize 1000% -flatten hiero_A1.pnm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The 29x38 grey+alpha input becomes a blurry 490 x 580 greymap surrounded by whitespace.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/hiero_A1_pnm.png&#34;
	width=&#34;490&#34;
	height=&#34;580&#34;
	srcset=&#34;https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/hiero_A1_pnm_hu_9f410aba6de34379.png 480w, https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/hiero_A1_pnm_hu_f7d173c01b7e0b0.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;84&#34;
		data-flex-basis=&#34;202px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This preparation is important, because a large blurry graymap will retain a lot more detail than the original image when a threshold is applied to convert it pure black and white:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/hiero_A1_threshold_compare.png&#34;
	width=&#34;580&#34;
	height=&#34;230&#34;
	srcset=&#34;https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/hiero_A1_threshold_compare_hu_bd402c2cf239aaa2.png 480w, https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/hiero_A1_threshold_compare_hu_5cb7964c9086d1d8.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;252&#34;
		data-flex-basis=&#34;605px&#34;
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;trace&#34;&gt;Trace
&lt;/h3&gt;&lt;p&gt;The &lt;code&gt;potrace&lt;/code&gt; program will threshold and trace the input image. Here, we will produce an SVG so that we can make it transparent.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;k&lt;/code&gt; value affects the threshold operation. It can be increased for a bolder, darker glyph, or reduced for a finer one.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;potrace hiero_A1.pnm -k 0.30 --svg
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This gives you an SVG with padding:&lt;/p&gt;
&lt;p&gt;&lt;div class=&#34;img-canvas-outer&#34;&gt;
&lt;a href=&#34;https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/hiero_A1.svg&#34; class=&#34;img-canvas-link  img-xxs&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/hiero_A1.svg&#34;
	
	
	
	loading=&#34;lazy&#34;
	
	
	    class=&#34;img-canvas-inner&#34; 
	
&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;If you only want a vector, then you can stop here. The next steps will reproduce a smaller PNG with transparency and the correct padding.&lt;/p&gt;
&lt;p&gt;I couldn&amp;rsquo;t find a reliable way to programmatically crop the image back to its original padding as an SVG, but in my case I needed to convert it back to a bitmap anyway, so I cropped it later.&lt;/p&gt;
&lt;h3 id=&#34;render&#34;&gt;Render
&lt;/h3&gt;&lt;p&gt;Use Inkscape to convert the SVG back to a large PNG. The output size here is twice as large as the file we traced, just to leave plenty of pixels to work with.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;inkscape -z -e hiero_A1_big.png hiero_A1.svg -w &lt;span class=&#34;m&#34;&gt;980&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Like the SVG, there is still a lot of empty space surrounding the image here. The image is now a PNG with a transparent background, and unlike the file we traced, the edges of the curves are now anti-aliased.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/hiero_A1_big-1.png&#34;
	width=&#34;980&#34;
	height=&#34;1160&#34;
	srcset=&#34;https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/hiero_A1_big-1_hu_5719e2eb8faec0e1.png 480w, https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/hiero_A1_big-1_hu_e4523c40d961750c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;84&#34;
		data-flex-basis=&#34;202px&#34;
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;crop&#34;&gt;Crop
&lt;/h3&gt;&lt;p&gt;Everything is 20x its original size, to get the image, we need to drop 200px of padding from the left and top, then read 580x760 pixels (20 times the 29x38 start).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;convert hiero_A1_big.png -crop 580x760+200+200 hiero_A1_cropped.png
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This produces a 580x760 image in the same aspect ratio as the original input file.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/hiero_A1_cropped.png&#34;
	width=&#34;580&#34;
	height=&#34;760&#34;
	srcset=&#34;https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/hiero_A1_cropped_hu_f3ca0ac047011465.png 480w, https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/hiero_A1_cropped_hu_f942e20e2446ad26.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxxs&#34; 
		data-flex-grow=&#34;76&#34;
		data-flex-basis=&#34;183px&#34;
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;scale-down&#34;&gt;Scale down
&lt;/h3&gt;&lt;p&gt;In my case, I only needed to &lt;em&gt;double&lt;/em&gt; the resolution of the input file, so I scaled this file down from there.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;hiero_A1_cropped.png -resize 58x76 hiero_A1_outp1.png
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/hiero_A1_outp1.png&#34;
	width=&#34;58&#34;
	height=&#34;76&#34;
	srcset=&#34;https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/hiero_A1_outp1_hu_7795baf6f1aaea7e.png 480w, https://mike42.me/blog/2018-04-raster-to-vector-conversion-tips/hiero_A1_outp1_hu_a9ecddc08b950bdf.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;76&#34;
		data-flex-basis=&#34;183px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Success!&lt;/p&gt;
&lt;h2 id=&#34;as-a-script&#34;&gt;As a script
&lt;/h2&gt;&lt;p&gt;These steps are a breakdown of a script that I wrote for doubling the size of a PNG image so that it would look better on newer high-DPI displays.&lt;/p&gt;
&lt;p&gt;Usage:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./tracepng.sh foo.png
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Where &lt;code&gt;tracepng.sh&lt;/code&gt; is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# A script to upscale small bitmaps in PNG format.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Pad, upscale, trace, render, crop then downscale.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$#&lt;/span&gt; !&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Usage &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$0&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; input.png&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -exu
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Names of all the files we will produce&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;INP_FILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;SVG_FILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;INP_FILE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;%.*&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;.svg&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;PNM_FILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;INP_FILE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;%.*&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;.pnm&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;LARGE_FILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;INP_FILE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;%.*&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;_big.png&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;LARGE_FILE_CROPPED&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;INP_FILE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;%.*&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;_cropped.png&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;OUTP_FILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;INP_FILE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;%.*&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;_outp1.png&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;COMPARISON_FILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;INP_FILE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;%.*&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;_outp2.png&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Width originally&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# https://stackoverflow.com/questions/4670013/fast-way-to-get-image-dimensions-not-filesize&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;IMG_WIDTH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;identify -format &lt;span class=&#34;s2&#34;&gt;&amp;#34;%w&amp;#34;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$INP_FILE&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;IMG_HEIGHT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;identify -format &lt;span class=&#34;s2&#34;&gt;&amp;#34;%h&amp;#34;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$INP_FILE&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;TARGET_WIDTH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$((&lt;/span&gt;IMG_WIDTH &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;TARGET_HEIGHT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$((&lt;/span&gt;IMG_HEIGHT &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Make huge raster w/ border (whitespace is your friend for black/white interpolation and tracing), then convert to SVG&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;convert &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;INP_FILE&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt; -bordercolor white -border 10x10 -resize 1000% -flatten &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;PNM_FILE&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# https://en.wikipedia.org/wiki/Potrace&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;potrace &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;PNM_FILE&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt; -k 0.30 --svg &amp;gt; &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;SVG_FILE&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Target width for intermediate file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;EXPANDED_WIDTH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$((&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;IMG_WIDTH &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;EXPANDED_HEIGHT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$((&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;IMG_HEIGHT &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;INNER_WIDTH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$((&lt;/span&gt;IMG_WIDTH &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;INNER_HEIGHT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$((&lt;/span&gt;IMG_HEIGHT &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# https://stackoverflow.com/questions/9853325/how-to-convert-a-svg-to-a-png-with-image-magick&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;inkscape -z -e &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LARGE_FILE&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;SVG_FILE&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt; -w &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;EXPANDED_WIDTH&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Cut new edges off&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# http://www.imagemagick.org/Usage/crop/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;convert &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LARGE_FILE&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt; -crop &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;INNER_WIDTH&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;x&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;INNER_HEIGHT&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;+200+200 &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LARGE_FILE_CROPPED&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;convert &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LARGE_FILE_CROPPED&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt; -resize &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;TARGET_WIDTH&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;x&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;TARGET_HEIGHT&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;OUTP_FILE&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;acknowledgment&#34;&gt;Acknowledgment
&lt;/h2&gt;&lt;p&gt;The images here are from &lt;a class=&#34;link&#34; href=&#34;https://www.mediawiki.org/wiki/Extension:WikiHiero&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;WikiHiero&lt;/a&gt;, and can be remixed under the GNU General Public License 2.0.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Git Introductory Material - Tips for Users, Admins and Git Champions</title>
        <link>https://mike42.me/blog/2018-03-git-introductory-material</link>
        <pubDate>Thu, 05 Apr 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-03-git-introductory-material</guid>
        <description>&lt;p&gt;This is a collection of tips that I have found useful for introducing software developers to the Git version control system.&lt;/p&gt;
&lt;h2 id=&#34;bookmarks-for-reference&#34;&gt;Bookmarks for reference
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.atlassian.com/git/tutorials/comparing-workflows/feature-branch-workflow&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;The &amp;ldquo;feature branch&amp;rdquo; workflow&lt;/a&gt; as documented by Atlassian.&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/k88hudson/git-flight-rules&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Flight manual&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://learngitbranching.js.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Git simulator&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;for-users&#34;&gt;For users
&lt;/h2&gt;&lt;p&gt;When you say that you use Git, most developers will assume that you are familiar with the Git CLI. Regardless of whether you plan to use the CLI long-term, when you do a web search to find out something about Git, you should be prepared to read answers that apply to the Git CLI.&lt;/p&gt;
&lt;p&gt;Since you will be asking a lot of questions in the first few weeks, you will have less work to do if you use the same interface as everybody else. Rest assured that there are plenty of graphical tools and IDE plugins that you can try out later.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takeaway&lt;/strong&gt;: Use the Git CLI while you are learning&lt;/p&gt;
&lt;p&gt;If you have more than one person working with the code, then you will want to share your repository between them.&lt;/p&gt;
&lt;p&gt;You need product that meets your budget, workflow, security and licensing needs: As of 2018, you really only need to consider GitHub, Bitbucket, Phabricator or GitLab to make a thorough comparison.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takeaway&lt;/strong&gt;: Use a collaborative environment that supports &amp;lsquo;pull requests&amp;rsquo;&lt;/p&gt;
&lt;h2 id=&#34;repository-admins&#34;&gt;Repository admins
&lt;/h2&gt;&lt;p&gt;Aim to make your setup both beginner-friendly, and beginner-proof.&lt;/p&gt;
&lt;p&gt;Git is not very opinionated, and has features which will support many advanced workflows. I would suggest that you save these features until you have a critical mass of experienced users who are comfortable troubleshooting them. The feature-branch workflow is beginner-friendly.&lt;/p&gt;
&lt;p&gt;Ensure that your whole team has mastered the basics before you try to get creative.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takeaway&lt;/strong&gt;: Just use the feature branch workflow initially&lt;/p&gt;
&lt;p&gt;There are a few switches that you should set in your system to prevent mistakes from disrupting users who do the right thing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;disable forced-push on the &lt;code&gt;master&lt;/code&gt; branch&lt;/li&gt;
&lt;li&gt;require a pull request and one approval to modify the &lt;code&gt;master&lt;/code&gt; branch&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The name of these settings will depend on the software you are hosting on, but for example, on GitHub, this is known as a &amp;ldquo;protected branch&amp;rdquo;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-03-git-introductory-material/2018-03-git-intro.png&#34;
	width=&#34;2586&#34;
	height=&#34;726&#34;
	srcset=&#34;https://mike42.me/blog/2018-03-git-introductory-material/2018-03-git-intro_hu_432725690c38159d.png 480w, https://mike42.me/blog/2018-03-git-introductory-material/2018-03-git-intro_hu_9a33101ed39e594e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;356&#34;
		data-flex-basis=&#34;854px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;These settings prevent people from re-writing history on the main branch, which is bad Git etiquette. Usually people are trying to re-write history with good intentions, such as trying to scrub credentials, huge files, or other extras that were accidentally included.&lt;/p&gt;
&lt;p&gt;Good software process aside, a lightweight code review process will make unintended changes more visible, so that you can give developers a chance to fix their mistakes without propagating them to other developers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takeaway&lt;/strong&gt;: Don&amp;rsquo;t allow direct access to &lt;code&gt;main&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&#34;git-champions&#34;&gt;Git champions
&lt;/h2&gt;&lt;p&gt;There are a few setup steps that users may not discover on their own, which avoid common frustrations.&lt;/p&gt;
&lt;p&gt;A classic beginner complaint about Git is that it makes you enter passwords all the time. Usually what is really happening here is that the user is working with a repository which was cloned over HTTPS, and has not set up SSH keys.&lt;/p&gt;
&lt;p&gt;Using SSH keys involves generating a key and uploading the public portion of the key to your hosting software. Subsequently, you will never be prompted for credentials.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takeaway&lt;/strong&gt;: Show users how to clone with SSH&lt;/p&gt;
&lt;p&gt;Immediately after you make your first commit, Git will point out that the author name has not been set, and suggest that you should amend the commit. I think that the experience is far better when this is configured proactively:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git config --global user.name &lt;span class=&#34;s2&#34;&gt;&amp;#34;Example Bob&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git config --global user.email &lt;span class=&#34;s2&#34;&gt;&amp;#34;bob@example.com&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first time that this user finds a merge conflict, they will appreciate having a graphical, point-and-click merge like &lt;code&gt;meld&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Follow OS-specific instructions, then run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git config --global difftool meld
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Takeaway&lt;/strong&gt;: Step new users through the user and &lt;code&gt;difftool&lt;/code&gt; settings.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;The dominance of Git as a software revision control tool means that it&amp;rsquo;s worth investing some time to learn it properly.&lt;/p&gt;
&lt;p&gt;If you get one thing out of this post, though, it&amp;rsquo;s that you shouldn&amp;rsquo;t attempt to be creative about your use of Git until you know what you are doing.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve tried to avoid mentioning intermediate or advanced features in this post. As you become more comfortable with the basics, you can use the flight rules and simulator at the top of the post to discover some of the things git can do, and the situations where you might want to use each feature.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to communicate with USB and networked devices from in-browser Javascript</title>
        <link>https://mike42.me/blog/2018-04-how-to-communicate-with-usb-and-networked-devices-from-in-browser-javascript</link>
        <pubDate>Thu, 29 Mar 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-04-how-to-communicate-with-usb-and-networked-devices-from-in-browser-javascript</guid>
        <description>&lt;p&gt;I recently combined a few tools on Linux to create a local Websocket listener, which could forward raw data to a USB printer, so that it could be accessed using Javascript in a web browser.&lt;/p&gt;
&lt;p&gt;Why would you want this? I have point of sale applications (POS) in mind, which need to send raw data to a printer. For these applications, the browser and operating system print systems are not appropriate, since they prompt, spool, and badly render pages by converting them to low-fidelity raster images.&lt;/p&gt;
&lt;p&gt;Web interfaces are becoming common for point-of-sale applications. The web page could be served from somewhere outside your local network, which is why we need to get the client-side Javascript involved.&lt;/p&gt;
&lt;h2 id=&#34;the-tools&#34;&gt;The tools
&lt;/h2&gt;&lt;p&gt;To run on the client computer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/novnc/websockify&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;websockify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;http://www.dest-unreach.org/socat/doc/socat.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;socat&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And to generate the print data on the webserver:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;escpos-php&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We will use these tools to provide some plumbing, so that we can retrieve the print data, and send it off to the printer from client-side Javascript.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-04-how-to-communicate-with-usb-and-networked-devices-from-in-browser-javascript/2018-04-js-printing-web-diagram.png&#34;
	width=&#34;476&#34;
	height=&#34;291&#34;
	srcset=&#34;https://mike42.me/blog/2018-04-how-to-communicate-with-usb-and-networked-devices-from-in-browser-javascript/2018-04-js-printing-web-diagram_hu_a7282ac3ebd67221.png 480w, https://mike42.me/blog/2018-04-how-to-communicate-with-usb-and-networked-devices-from-in-browser-javascript/2018-04-js-printing-web-diagram_hu_920cb0d41bbe5e84.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;163&#34;
		data-flex-basis=&#34;392px&#34;
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;client-computer&#34;&gt;Client computer
&lt;/h3&gt;&lt;p&gt;The client computer was a Linux desktop system. Both of the tools we need are available in the Debian repositories:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install websockify socat
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Listen for websocket connections on port &lt;code&gt;5555&lt;/code&gt; and pass them to &lt;code&gt;localhost:7000&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;websockify &lt;span class=&#34;m&#34;&gt;5555&lt;/span&gt; localhost:7000
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Listen for TCP connections on localhost port 7000 and pass them to the USB device (more advanced version of &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2015-04-how-to-use-a-raspberry-pi-as-a-print-server&#34; &gt;this previous post&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;socat -u TCP-LISTEN:7000,fork,reuseaddr,bind&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;127.0.0.1 OPEN:/dev/usb/lp0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;web-page&#34;&gt;Web page
&lt;/h3&gt;&lt;p&gt;I made a self-contained web-page to provide a button which requested a print file from the network and passed it to the local websocket.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-04-how-to-communicate-with-usb-and-networked-devices-from-in-browser-javascript/2018-04-js-printing-web-example.png&#34;
	width=&#34;1274&#34;
	height=&#34;590&#34;
	srcset=&#34;https://mike42.me/blog/2018-04-how-to-communicate-with-usb-and-networked-devices-from-in-browser-javascript/2018-04-js-printing-web-example_hu_8977e456e2753d23.png 480w, https://mike42.me/blog/2018-04-how-to-communicate-with-usb-and-networked-devices-from-in-browser-javascript/2018-04-js-printing-web-example_hu_c6b5bc2d3084a841.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;215&#34;
		data-flex-basis=&#34;518px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This is slightly modified from &lt;a class=&#34;link&#34; href=&#34;https://github.com/receipt-print-hq/chrome-raw-print/tree/master/example&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;a similar example that I used for a previous project&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;meta&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;charset&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;UTF-8&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;Web-based raw printing example&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;Web-based raw printing example&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;This snippet forwards raw data to a local websocket.&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;form&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;input&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;button&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;onclick&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;directPrintBytes(printSocket, [0x1b, 0x40, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x0a, 0x1d, 0x56, 0x41, 0x03]);&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Print test string&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;input&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;button&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;onclick&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;directPrintFile(printSocket, &amp;#39;receipt-with-logo.bin&amp;#39;);&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Load and print &amp;#39;receipt-with-logo&amp;#39;&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;form&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * Retrieve binary data via XMLHttpRequest and print it.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;directPrintFile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// Get binary data
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;XMLHttpRequest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;responseType&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;arraybuffer&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;directPrintFile(): Making request for binary file&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;onload&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;oEvent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;directPrintFile(): Response received&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;arrayBuffer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Note: not req.responseText
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;arrayBuffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;result&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;directPrint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;arrayBuffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;alert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Failed, check the console for more info.&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * Extract binary data from a byte array print it.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;directPrintBytes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;bytes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;result&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;directPrint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Uint8Array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bytes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;alert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Failed, check the console for more info.&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * Send ArrayBuffer of binary data.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;directPrint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;printData&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// Type check
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;printData&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;instanceof&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ArrayBuffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;directPrint(): Argument type must be ArrayBuffer.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;printSocket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;readyState&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!==&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;printSocket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;OPEN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;directPrint(): Socket is not open!&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// Serialise, send.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Sending &amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;printData&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;byteLength&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34; bytes of print data.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;printSocket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;printData&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * Connect to print server on startup.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;printSocket&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;WebSocket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ws://localhost:5555&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;binary&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;printSocket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;binaryType&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;arraybuffer&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;printSocket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;onopen&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Socket is connected.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;printSocket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;onerror&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Socket error&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;printSocket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;onclose&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Socket is closed&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;webserver&#34;&gt;Webserver
&lt;/h3&gt;&lt;p&gt;On an Apache HTTP webserver, I uploaded the above webpage, and a file with some raw print data, called &lt;code&gt;receipt-with-logo.bin&lt;/code&gt;. This file was generated with &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;escpos-php&lt;/a&gt; and is available in the repository:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php/blob/development/test/integration/resources/output/receipt-with-logo.bin&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;receipt-with-logo.bin&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For reference, the test file &lt;code&gt;receipt-with-logo.bin&lt;/code&gt; looks like this when printed:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-04-how-to-communicate-with-usb-and-networked-devices-from-in-browser-javascript/receipt-with-logo-small.png&#34;
	width=&#34;302&#34;
	height=&#34;412&#34;
	srcset=&#34;https://mike42.me/blog/2018-04-how-to-communicate-with-usb-and-networked-devices-from-in-browser-javascript/receipt-with-logo-small_hu_b482542c5d13419d.png 480w, https://mike42.me/blog/2018-04-how-to-communicate-with-usb-and-networked-devices-from-in-browser-javascript/receipt-with-logo-small_hu_ebe8844906463b6f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;73&#34;
		data-flex-basis=&#34;175px&#34;
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;test&#34;&gt;Test
&lt;/h3&gt;&lt;p&gt;I opened up the web page on the client computer with &lt;code&gt;socat&lt;/code&gt;, &lt;code&gt;websockify&lt;/code&gt; and an Epson TM-T20II connected. After clicking the &amp;ldquo;Print&amp;rdquo; button, the file was sent to my printer. Success!&lt;/p&gt;
&lt;p&gt;Because I wasn&amp;rsquo;t closing the websocket connection, only one browser window could access the printer at a time. Still, it&amp;rsquo;s a good demo of the basic idea.&lt;/p&gt;
&lt;p&gt;To take this from an example to something you might deploy, you would basically just need to keep &lt;code&gt;socat&lt;/code&gt; and &lt;code&gt;websockify&lt;/code&gt; running in the background as a service (eg. via &lt;code&gt;systemd&lt;/code&gt;), close the socket when it&amp;rsquo;s not being used, and integrate it into a real app.&lt;/p&gt;
&lt;h2 id=&#34;different-printers-different-forwarding&#34;&gt;Different printers, different forwarding
&lt;/h2&gt;&lt;p&gt;The &lt;code&gt;socat&lt;/code&gt; tool can connect to USB, Serial, or Ethernet printers fairly easily.&lt;/p&gt;
&lt;h3 id=&#34;usb&#34;&gt;USB
&lt;/h3&gt;&lt;p&gt;Forward TCP connections from port 7000 to the receipt printer at &lt;code&gt;/dev/usb/lp0&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;socat TCP4-LISTEN:7000,fork /dev/usb/lp0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can also access the device files directly under &lt;code&gt;/sys/bus/usb/devices/&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&#34;serial&#34;&gt;Serial
&lt;/h3&gt;&lt;p&gt;Forward TCP connections from port 7000 to the receipt printer at &lt;code&gt;/dev/usb/ttyS0&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;socat TCP4-LISTEN:7000,fork /dev/usb/ttyS0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;network&#34;&gt;Network
&lt;/h3&gt;&lt;p&gt;Forward TCP connections from port 7000 to the receipt printer at &lt;code&gt;10.1.2.3:9100&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;socat -u TCP-LISTEN:7000,fork,reuseaddr,bind&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;127.0.0.1 TCP4-CONNECT:10.1.2.3:9100
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can forward websocket connections directly to an Ethernet printer with &lt;code&gt;websockify&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;socat -u TCP-LISTEN:7000,fork,reuseaddr,bind&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;127.0.0.1 localhost:7000
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;other-types-of-printer&#34;&gt;Other types of printer
&lt;/h3&gt;&lt;p&gt;If you have another type of printer, such as one accessible only via &lt;code&gt;smbclient&lt;/code&gt; or &lt;code&gt;lpr&lt;/code&gt;, then you will need to write a helper script.&lt;/p&gt;
&lt;p&gt;Direct printing is faster, so I don&amp;rsquo;t use this method. Check the &lt;a class=&#34;link&#34; href=&#34;http://www.dest-unreach.org/socat/doc/socat-exec.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;socat EXEC documentation&lt;/a&gt; or &lt;code&gt;man socat&lt;/code&gt; if you want to try this.&lt;/p&gt;
&lt;h2 id=&#34;future&#34;&gt;Future
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;ve had &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php/issues?q=internet&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;a lot of questions&lt;/a&gt; on the escpos-php bug tracker from users who are attempting to print from cloud-hosted apps, which is why I tried this setup.&lt;/p&gt;
&lt;p&gt;The browser is a moving target. I have previously written &lt;a class=&#34;link&#34; href=&#34;https://github.com/receipt-print-hq/chrome-raw-print&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;receipt-print-hq/chrome-raw-print&lt;/a&gt;, a dedicated app for forwarding WebSocket connections to USB, but that will stop working in a few months when Chrome apps are discontinued. Some time later, WebUSB should become available to make this type of printer available in the browser, which should be invaluable for connecting to accessories in point-of-sale setups.&lt;/p&gt;
&lt;p&gt;The available tools for generating ESC/POS (receipt printer) binary from the browser are a long way off reaching feature parity with the likes of &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;escpos-php&lt;/a&gt; and &lt;a class=&#34;link&#34; href=&#34;https://github.com/python-escpos/python-escpos&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;python-escpos&lt;/a&gt;. If you are looking for a side-project, then this a good choice.&lt;/p&gt;
&lt;p&gt;Lastly, the socat &lt;code&gt;-u&lt;/code&gt; flag makes this all unidirectional, but many types of devices (not just printers) can respond to commands. I couldn&amp;rsquo;t get the end-to-end path to work without this flag, so don&amp;rsquo;t expect to be able to read from the printer without doing some extra work.&lt;/p&gt;
&lt;h2 id=&#34;useful-links&#34;&gt;Useful links
&lt;/h2&gt;&lt;p&gt;Some links that I found while setting this up-&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;http://blog.mgechev.com/2015/02/06/parsing-binary-protocol-data-javascript-typedarrays-blobs/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Processing Binary Protocols with Client-Side JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://gist.github.com/hagino3000/1447986&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;hagino3000/client.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/Tecdiary/ppp&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;PHP POS Print (Local Server)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;get-the-code&#34;&gt;Get the code
&lt;/h2&gt;&lt;p&gt;The code which I used to build this demo is available in the &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-snippets/tree/master/js-binary-websocket-demo&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/escpos-snippets&lt;/a&gt; repository on GitHub.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Automating LXC container creation with Ansible</title>
        <link>https://mike42.me/blog/2018-03-automating-lxc-container-creation-with-ansible</link>
        <pubDate>Thu, 22 Mar 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-03-automating-lxc-container-creation-with-ansible</guid>
        <description>&lt;p&gt;LXC is a Linux container technology that I use for both development and production setups hosted on Debian.&lt;/p&gt;
&lt;p&gt;This type of container acts a lot like a lightweight virtual machine, and can be administered with standard linux tools. When configured over SSH, you should be able to use the same scripts against either an LXC container or VM without noticing the difference.&lt;/p&gt;
&lt;p&gt;This setup will provision &amp;ldquo;privileged&amp;rdquo; containers behind a NAT, which is a setup that is most useful for a developer workstation. A setup in a server rack would be more likely to use &amp;ldquo;unprivileged&amp;rdquo; containers on a host bridge, which is slightly more complex to set up. The good news is that the guest container will behave very similarly once it&amp;rsquo;s provisioned, so developers shouldn&amp;rsquo;t need to adapt their code to those details either.&lt;/p&gt;
&lt;h2 id=&#34;manual-setup-of-an-lxc-container&#34;&gt;Manual setup of an LXC container
&lt;/h2&gt;&lt;p&gt;You need to know how to do something manually before you can automate it.&lt;/p&gt;
&lt;p&gt;The best reference guide for this is &lt;a class=&#34;link&#34; href=&#34;https://wiki.debian.org/LXC&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;the current Debian documentation&lt;/a&gt;. This is a shorter version of those instructions, with only the parts we need.&lt;/p&gt;
&lt;h3 id=&#34;packages&#34;&gt;Packages
&lt;/h3&gt;&lt;p&gt;Everything you need for LXC is in the &lt;code&gt;lxc&lt;/code&gt; Debian package:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo apt-get install lxc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;The following additional packages will be installed:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  bridge-utils debootstrap liblxc1 libpam-cgfs lxcfs python3-lxc uidmap
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Suggested packages:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  btrfs-progs lvm2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;The following NEW packages will be installed:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  bridge-utils debootstrap liblxc1 libpam-cgfs lxc lxcfs python3-lxc uidmap
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0 upgraded, 8 newly installed, 0 to remove and 0 not upgraded.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Need to get 1,367 kB of archives.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;After this operation, 3,762 kB of additional disk space will be used.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Do you want to continue? [Y/n] y
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;network&#34;&gt;Network
&lt;/h3&gt;&lt;p&gt;Enable the LXC bridge, and start it up:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;USE_LXC_BRIDGE=&amp;#34;true&amp;#34;&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sudo tee -a /etc/default/lxc-net
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo systemctl start lxc-net
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This gives you an internal network for your containers to connect to. From there, they can connect out to the Internet, or communicate with each-other:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;3: lxcbr0: &amp;lt;NO-CARRIER,BROADCAST,MULTICAST,UP&amp;gt; mtu 1500 qdisc noqueue state DOWN group default qlen 1000
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    link/ether 00:16:3e:00:00:00 brd ff:ff:ff:ff:ff:ff
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    inet 10.0.3.1/24 scope global lxcbr0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       valid_lft forever preferred_lft forever
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;defaults&#34;&gt;Defaults
&lt;/h3&gt;&lt;p&gt;Instruct LXC to attach a NIC to this network each time you make a containers:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo vi /etc/lxc/default.conf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Replace that file with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lxc.network.type = veth
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lxc.network.link = lxcbr0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lxc.network.flags = up
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lxc.network.hwaddr = 00:16:3e:xx:xx:xx
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can then create a &amp;rsquo;test1&amp;rsquo; box, using the Debian image online. Note the output here indicates that the container has no SSH server or root password.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo lxc-create --name test1 --template=download -- --dist=debian --release=stretch --arch=amd64
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Setting up the GPG keyring
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Downloading the image index
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Downloading the rootfs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Downloading the metadata
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;The image cache is now ready
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Unpacking the rootfs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;You just created a Debian container (release=stretch, arch=amd64, variant=default)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;To enable sshd, run: apt-get install openssh-server
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;For security reason, container images ship without user accounts
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;and without a root password.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Use lxc-attach or chroot directly into the rootfs to set a root password
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;or create user accounts.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The container is created in a stopped state. Start it up now:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo lxc-start --name test1 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It now appears with an automatically assigned IP.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo lxc-ls --fancy
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;NAME  STATE   AUTOSTART GROUPS IPV4       IPV6 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;test1 RUNNING 0         -      10.0.3.250 -    
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;set-up-login-access&#34;&gt;Set up login access
&lt;/h3&gt;&lt;p&gt;Start by getting your SSH public key ready. You can locate at &lt;code&gt;~/.ssh/id_rsa.pub&lt;/code&gt;. You can use &lt;code&gt;ssh-keygen&lt;/code&gt; to create this if it doesn&amp;rsquo;t exist.&lt;/p&gt;
&lt;p&gt;To SSH in, you need to install an SSH server, and get this public key into the &lt;code&gt;/root/authorized_keys&lt;/code&gt; file in the container.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo lxc-attach --name test1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@test1:/# apt-get update
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@test1:/# apt-get -y install openssh-server
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@test1:/# mkdir -p ~/.ssh
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@test1:/# echo &amp;#34;ssh-rsa (public key) user@host&amp;#34; &amp;gt;&amp;gt; ~/.ssh/authorized_keys
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Type &lt;code&gt;exit&lt;/code&gt; or press &lt;code&gt;Ctrl+D&lt;/code&gt; to quit, and try to log in from your regular account over SSH:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ssh root@10.0.3.250
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;The authenticity of host &amp;#39;10.0.3.250 (10.0.3.250)&amp;#39; can&amp;#39;t be established.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ECDSA key fingerprint is SHA256:EWH1zUW4BEZUzfkrFL1K+24gTzpd8q8JRVc5grKaZfg.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Are you sure you want to continue connecting (yes/no)? yes
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Warning: Permanently added &amp;#39;10.0.3.250&amp;#39; (ECDSA) to the list of known hosts.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Linux test1 4.14.0-3-amd64 #1 SMP Debian 4.14.13-1 (2018-01-14) x86_64
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;The programs included with the Debian GNU/Linux system are free software;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;the exact distribution terms for each program are described in the
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;individual files in /usr/share/doc/*/copyright.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;permitted by applicable law.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@test1:~# 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And you&amp;rsquo;re in. You may be surprised how minimal the LXC images are by default, but the full power of Debian is available from &lt;code&gt;apt-get&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This container is not configured to start on boot. For that, you would add this line to &lt;code&gt;/var/lib/lxc/test1/config&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lxc.start.auto = 1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;teardown&#34;&gt;Teardown
&lt;/h3&gt;&lt;p&gt;To stop the &lt;code&gt;test1&lt;/code&gt; container and then delete it permanently, run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo lxc-stop --name test1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo lxc-destroy --name test1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;automated-setup-of-lxc-containers-with-ansible&#34;&gt;Automated setup of LXC containers with Ansible
&lt;/h2&gt;&lt;p&gt;Now that the basic steps have been done manually, I&amp;rsquo;ll show you how to Ansible to create a set of LXC containers. If you haven&amp;rsquo;t used it before, Ansible is an automation tool for managing computers. At its heart, it just logs into machines and runs things. These scripts are an approximate automation of the steps above, so that you can create 10 or 100 containers at once if you need to.&lt;/p&gt;
&lt;p&gt;I use this method on a small project that I maintain on GitHub called &lt;a href=&#34;https://github.com/mike42/ansible-live&#34;&gt;ansible-live&lt;/a&gt;, which bootstraps a containerized training environment for Ansible.&lt;/p&gt;
&lt;h3 id=&#34;host-setup&#34;&gt;Host setup
&lt;/h3&gt;&lt;p&gt;You need a few packages and config files on the host. In addition to the &lt;code&gt;lxc&lt;/code&gt; package, we need &lt;code&gt;lxc-dev&lt;/code&gt; and the &lt;code&gt;lxc-python2&lt;/code&gt; python package to manage the containers from Ansible:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;hosts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;localhost&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;become&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;vars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;interface&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;lxcbr0&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;tasks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;apt lxc packages are installed on host&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;apt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;name={{ item }}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;with_items&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;lxc&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;lxc-dev&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;python-pip&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;copy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;dest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;/etc/default/lxc-net&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;        USE_LXC_BRIDGE=&amp;#34;true&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;copy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;dest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;/etc/lxc/default.conf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;        lxc.network.type = veth
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;        lxc.network.link = {{ interface }}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;        lxc.network.flags = up
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;        lxc.network.hwaddr = 00:16:3e:xx:xx:xx&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;service&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;lxc-net&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;started&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;pip lxc packages are installed on host&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;pip&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;{{ item }}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;with_items&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;lxc-python2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;run_once&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This can be executed with this command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ansible-playbook setup.yml --ask-become-pass --diff
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;container-creation&#34;&gt;Container creation
&lt;/h3&gt;&lt;p&gt;Add a file called &lt;code&gt;inventory&lt;/code&gt; to specify the containers to use. These are two IP addresses in the range of the LXC network.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb1 ansible_host=10.0.3.100
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb2 ansible_host=10.0.3.101
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For local work, I find it easier to set an IP address with Ansible and use the &lt;code&gt;/etc/hosts&lt;/code&gt; file, which is why IP addresses are included here. Without it, you need to wait for each container to boot, then detect its IP address before you can log in.&lt;/p&gt;
&lt;p&gt;Add this to &lt;code&gt;setup.yml&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;hosts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;all&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;become&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;vars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;interface&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;lxcbr0&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;tasks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Load in local SSH key path&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;set_fact&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;my_ssh_key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;{{ lookup(&amp;#39;env&amp;#39;,&amp;#39;HOME&amp;#39;) }}/.ssh/id_rsa.pub&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;interface device exists&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ip addr show {{ interface }}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;changed_when&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;run_once&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Local user has an SSH key&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;stat {{ my_ssh_key }}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;changed_when&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;run_once&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;containers exist and have local SSH key&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;delegate_to&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;localhost&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;lxc_container&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;{{ inventory_hostname }}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;template&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;debian&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;started&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;template_options&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;--&lt;span class=&#34;l&#34;&gt;release stretch&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_config&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;- &lt;span class=&#34;s2&#34;&gt;&amp;#34;lxc.network.type = veth&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;- &lt;span class=&#34;s2&#34;&gt;&amp;#34;lxc.network.flags = up&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;- &lt;span class=&#34;s2&#34;&gt;&amp;#34;lxc.network.link = {{ interface }}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;- &lt;span class=&#34;s2&#34;&gt;&amp;#34;lxc.network.ipv4 = {{ ansible_host }}/24&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;- &lt;span class=&#34;s2&#34;&gt;&amp;#34;lxc.network.ipv4.gateway = auto&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;        if [ ! -d ~/.ssh ]; then
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;          mkdir ~/.ssh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;          echo &amp;#34;{{ lookup(&amp;#39;file&amp;#39;, my_ssh_key) }}&amp;#34; | tee -a ~/.ssh/authorized_keys
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;          sed -i &amp;#39;s/dhcp/manual/&amp;#39; /etc/network/interfaces &amp;amp;&amp;amp; systemctl restart network
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;        fi&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the next block of &lt;code&gt;setup.yml&lt;/code&gt;, use &lt;code&gt;keyscan&lt;/code&gt; to get the SSH keys of each machine as it becomes available.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;hosts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;all&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;become&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;serial&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;tasks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;wait_for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;host={{ ansible_host }} port=22&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;container key is up-to-date locally&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;shell&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ssh-keygen -R {{ ansible_host }}; (ssh-keyscan {{ ansible_host }} &amp;gt;&amp;gt; ~/.ssh/known_hosts)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Lastly, jump in via SSH and install python. This is required for any follow-up configuration that uses Ansible.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;hosts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;all&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;gather_facts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;no&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;vars&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;ansible_user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;root&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;tasks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;install python on target machines&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;raw&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;which python || (apt-get -y update &amp;amp;&amp;amp; apt-get install -y python)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, you can use this one-liner to create the two containers listed in the &lt;code&gt;inventory&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ansible-playbook setup.yml --ask-become-pass --diff
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;scaling-to-hundreds-of-containers&#34;&gt;Scaling to hundreds of containers
&lt;/h3&gt;&lt;p&gt;Now that you have created two containers, it is easy enough to see how you would make 20 containers by making a bigger inventory:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; i in &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;1..20&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; deb&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;printf&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;%03d&amp;#34;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;.example.com &lt;span class=&#34;nv&#34;&gt;ansible_host&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;10.0.3.&lt;span class=&#34;k&#34;&gt;$((&lt;/span&gt;i+1&lt;span class=&#34;k&#34;&gt;))&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;done&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; tee inventory
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb001.example.com &lt;span class=&#34;nv&#34;&gt;ansible_host&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;10.0.3.2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb002.example.com &lt;span class=&#34;nv&#34;&gt;ansible_host&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;10.0.3.3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb003.example.com &lt;span class=&#34;nv&#34;&gt;ansible_host&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;10.0.3.4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can then run the playbook again:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ansible-playbook -i inventory setup.yml --ask-become-pass
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This produces 20 machines after a few minutes.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-03-automating-lxc-container-creation-with-ansible/2018-03-many-containers.png&#34;
	width=&#34;2400&#34;
	height=&#34;766&#34;
	srcset=&#34;https://mike42.me/blog/2018-03-automating-lxc-container-creation-with-ansible/2018-03-many-containers_hu_c7d5f5626475b7.png 480w, https://mike42.me/blog/2018-03-automating-lxc-container-creation-with-ansible/2018-03-many-containers_hu_bbd2b0f99f8d2154.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;313&#34;
		data-flex-basis=&#34;751px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The tasks running during this setup were mostly &lt;code&gt;rync&lt;/code&gt; processes (copying the container contents), plus the network waiting to retrieve &lt;code&gt;python&lt;/code&gt; many times. If you need to optimise to frequent container spin-ups, LXC supports
storage back-ends that have copy-on-write, and you can either cache package downloads with a local webserver, or build some packages into the template.&lt;/p&gt;
&lt;p&gt;Running these 20 containers plus a Debian desktop, I found that my computer was using just 2.9GB of RAM, so I figured I would test 200 empty containers at once.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;for i in {1..200}; do echo deb$(printf &amp;#34;%03d&amp;#34; $i).example.com ansible_host=10.0.3.$((i+1)); done &amp;gt; inventory
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ansible -i inventory setup.yml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It took truly a very long time to add Python to each install, but the result is what I would expect:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo lxc-ls --fancy
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;NAME               STATE   AUTOSTART GROUPS IPV4       IPV6 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb001.example.com RUNNING &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;         -      10.0.3.2   -    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb002.example.com RUNNING &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;         -      10.0.3.3   -    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb003.example.com RUNNING &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;         -      10.0.3.4   -    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb198.example.com RUNNING &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;         -      10.0.3.199 -    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb199.example.com RUNNING &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;         -      10.0.3.200 -    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb200.example.com RUNNING &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;         -      10.0.3.201 -    
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The base resource usage of an idle container is absolutely tiny, around 13 megabytes - the system moved from 2.9GB to 5.4GB of RAM used when I added 180 containers. Containers clearly have a lower overhead than VM&amp;rsquo;s, since no RAM has been reserved here.&lt;/p&gt;
&lt;h2 id=&#34;software-updates&#34;&gt;Software updates
&lt;/h2&gt;&lt;p&gt;The containers are updated just like regular VM&amp;rsquo;s-&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get update
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get dist-upgrade
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;backups&#34;&gt;Backups
&lt;/h2&gt;&lt;p&gt;In this setup, the container&amp;rsquo;s content is stored under &lt;code&gt;/var/lib/lxc/&lt;/code&gt;. As long as the container is stopped, you can safely use &lt;code&gt;tar&lt;/code&gt; or &lt;code&gt;rsync&lt;/code&gt; to make a full copy:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo tar -czf deb001.20180209.tar.gz /var/lib/lxc/deb001.example.com/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rsync -avz /var/lib/lxc/deb001.example.com/ remote-computer@example.com:/backups/deb001.example.com/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Full-machine snapshots are also available on the Ceph or LVM back-ends, if you use those.&lt;/p&gt;
&lt;h3 id=&#34;teardown-1&#34;&gt;Teardown
&lt;/h3&gt;&lt;p&gt;The same Ansible module can be used to delete all of these machines in a few seconds.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;hosts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;all&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;connection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;become&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;tasks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Containers do not exist&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;delegate_to&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;localhost&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;lxc_container&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;{{ inventory_hostname }}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;absent&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ansible-playbook -i inventory teardown.yml --ask-become-pass
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;Hopefully this post has given you some insight into one way that Linux containers can be used. I have found LXC to be a great technology to work with for standalone setups, and regularly use the same scripts to configure either an LXC container or a VM&amp;rsquo;s depending on the target environment.&lt;/p&gt;
&lt;p&gt;The low resource usage also means that I can run fairly complex setups on a laptop, where the overhead of large VM&amp;rsquo;s would be prohibitive.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t think that LXC is directly comparable to full container ecosystems like Docker, since they are geared towards different use cases. These are both useful tools to know, and have complementary strengths.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Using custom fonts to add new glyphs to an Epson printer</title>
        <link>https://mike42.me/blog/2018-03-using-custom-fonts-to-add-new-glyphs-to-an-epson-printer</link>
        <pubDate>Thu, 15 Mar 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-03-using-custom-fonts-to-add-new-glyphs-to-an-epson-printer</guid>
        <description>&lt;p&gt;I develop a printer driver for ESC/POS receipt printers, and regularly get feature requests for encoding text in the Chinese, Japanese and Korean languages (&amp;ldquo;CJK&amp;rdquo;).&lt;/p&gt;
&lt;p&gt;I have recently been looking for a way to add support for these on receipt printers that have no native ability to render them, and thought I would write a bit about some progress so far.&lt;/p&gt;
&lt;p&gt;I previously wrote a bit about &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2018-03-how-to-print-custom-currency-symbols-on-a-receipt-printer&#34; &gt;printing individual bitmaps&lt;/a&gt; for each character, where here I am aiming to print entire &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Writing_system&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;scripts&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;background&#34;&gt;Background
&lt;/h2&gt;&lt;p&gt;Programmers usually deal with text in UTF-8, but receipt printers don&amp;rsquo;t. Instead, they still use a series of legacy code pages to represent non-ASCII text. Mapping arbitrary text to something understood by these printers is a huge challenge.&lt;/p&gt;
&lt;p&gt;The escpos-php driver will automatically map a lot of western scripts to these code pages. However, if you attempt to send an example string like &amp;ldquo;日本語&amp;rdquo; to escpos-php currently, the driver will substitute it with &amp;ldquo;???&amp;rdquo;, since it doesn&amp;rsquo;t know how to convert them to ESC/POS.&lt;/p&gt;
&lt;p&gt;On some printers, there are native commands to print Japanese, but for a driver project, we need something with broad compatibility. So, I decided to try to get this working on an Epson TM-T20 variant which has no CJK fonts.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-03-using-custom-fonts-to-add-new-glyphs-to-an-epson-printer/2015-03-printer-top.jpg&#34;
	width=&#34;2460&#34;
	height=&#34;1816&#34;
	srcset=&#34;https://mike42.me/blog/2018-03-using-custom-fonts-to-add-new-glyphs-to-an-epson-printer/2015-03-printer-top_hu_eb82a29bb98b6db0.jpg 480w, https://mike42.me/blog/2018-03-using-custom-fonts-to-add-new-glyphs-to-an-epson-printer/2015-03-printer-top_hu_6227b6e59edbc1af.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;135&#34;
		data-flex-basis=&#34;325px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I started by making a new standalone test script, which converts text input into ESC/POS using a cut-down version of the escpos-php printer driver.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;file_get_contents&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;php://stdin&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;php://stdout&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I then modified this to print arbitrary UTF-8 text with a local bitmap font. These next sections go through some of the things I had to write to get it all working.&lt;/p&gt;
&lt;h2 id=&#34;character-representation&#34;&gt;Character representation
&lt;/h2&gt;&lt;p&gt;I decided to start with &lt;a class=&#34;link&#34; href=&#34;http://unifoundry.com/unifont.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;the GNU Unifont project&lt;/a&gt;, because it ships fixed-width binary fonts in a text format that can be parsed without a font library, is freely licensed, and has excellent coverage.&lt;/p&gt;
&lt;p&gt;So the first issue to solve was to do with font sizes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Unifont contains characters that are 8 or 16 pixels wide, that cover the entire Unicode Basic Multilingual Plane (BMP), at 16 characters tall.&lt;/li&gt;
&lt;li&gt;ESC/POS supports a fixed 12x24 or a smaller 9x17 font.&lt;/li&gt;
&lt;li&gt;ESC/POS fonts are submitted in a 24 pixel tall format regardless of print area.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since the characters would be surrounded by too much whitespace in the &amp;ldquo;Font A&amp;rdquo; (12x24) representation, I settled on printing in &amp;ldquo;Font B&amp;rdquo; (9x17), leaving a one-pixel space underneath, and to the right of each character. These pictures show how the glpyhs (grey) are laid out in the available print area (unused print area in white), in the available memory (unused memory in red).&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-03-using-custom-fonts-to-add-new-glyphs-to-an-epson-printer/2018-03-unifont-font.png&#34;
	width=&#34;72&#34;
	height=&#34;192&#34;
	srcset=&#34;https://mike42.me/blog/2018-03-using-custom-fonts-to-add-new-glyphs-to-an-epson-printer/2018-03-unifont-font_hu_fbda2f3bff2d9f9c.png 480w, https://mike42.me/blog/2018-03-using-custom-fonts-to-add-new-glyphs-to-an-epson-printer/2018-03-unifont-font_hu_98e93809d9dfaeca.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;37&#34;
		data-flex-basis=&#34;90px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2018-03-using-custom-fonts-to-add-new-glyphs-to-an-epson-printer/2018-03-unifont-font2.png&#34;
	width=&#34;144&#34;
	height=&#34;192&#34;
	srcset=&#34;https://mike42.me/blog/2018-03-using-custom-fonts-to-add-new-glyphs-to-an-epson-printer/2018-03-unifont-font2_hu_eba6cb28ea340424.png 480w, https://mike42.me/blog/2018-03-using-custom-fonts-to-add-new-glyphs-to-an-epson-printer/2018-03-unifont-font2_hu_5f55f8fba47f8287.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;75&#34;
		data-flex-basis=&#34;180px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Note that wider characters have a two-pixel dead-zone on the right. The non-printable 7 pixels at the bottom of the images are ignored by the printer.&lt;/p&gt;
&lt;p&gt;The format on the printer for each character stores bits in a column-major format, while most raster formats are row-major, so I wrote a quick converter to rotate the bits. The converter code is not very concise, so I&amp;rsquo;ll just share a screen capture here to give you an idea of what it looks like. The full code is linked at the end of this post.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-03-using-custom-fonts-to-add-new-glyphs-to-an-epson-printer/2018-03-unifont-code.png&#34;
	width=&#34;1670&#34;
	height=&#34;484&#34;
	srcset=&#34;https://mike42.me/blog/2018-03-using-custom-fonts-to-add-new-glyphs-to-an-epson-printer/2018-03-unifont-code_hu_e7001f765d863704.png 480w, https://mike42.me/blog/2018-03-using-custom-fonts-to-add-new-glyphs-to-an-epson-printer/2018-03-unifont-code_hu_f6155c40d2684c81.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;345&#34;
		data-flex-basis=&#34;828px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Lastly, the output size on paper was tiny, so I set the printer to double the size, which results in text that is around 50% larger than the default output.&lt;/p&gt;
&lt;h2 id=&#34;storage-of-fonts&#34;&gt;Storage of fonts
&lt;/h2&gt;&lt;p&gt;There is only space for 95 single-width characters in an ESC/POS font, but the scripts are much larger than this.&lt;/p&gt;
&lt;p&gt;I treated the font as a queue in this implementation. During the print-out, new characters are added to the font as necessary, and the font is re-written from the front as space runs out. This is also known as a FIFO cache eviction policy.&lt;/p&gt;
&lt;h2 id=&#34;input&#34;&gt;Input
&lt;/h2&gt;&lt;p&gt;I converted the string input to an array of Unicode code points to avoid canonicalisaton issues.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$chrArray&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;preg_split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;//u&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;PREG_SPLIT_NO_EMPTY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$codePoints&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;array_map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;IntlChar::ord&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chrArray&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;foreach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$codePoints&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$char&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;writeChar&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$char&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;IntlChar&lt;/code&gt; class is provided by an extension which is very useful but not widespread, which limits the portability of this code.&lt;/p&gt;
&lt;h2 id=&#34;result&#34;&gt;Result
&lt;/h2&gt;&lt;p&gt;I used the list of languages from the sidebar of a &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Car&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Wikipedia article&lt;/a&gt; as a test string, since it contains short strings in a large number of scripts.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat test.txt | php unifont-example.php &amp;gt; /dev/usb/lp0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The output contains a large number of correctly rendered scripts, including the CJK output, which was not previously possible on my printer.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-03-using-custom-fonts-to-add-new-glyphs-to-an-epson-printer/2018-03-unifont-text.png&#34;
	width=&#34;1024&#34;
	height=&#34;1039&#34;
	srcset=&#34;https://mike42.me/blog/2018-03-using-custom-fonts-to-add-new-glyphs-to-an-epson-printer/2018-03-unifont-text_hu_8cbc2a9b4ea8539b.png 480w, https://mike42.me/blog/2018-03-using-custom-fonts-to-add-new-glyphs-to-an-epson-printer/2018-03-unifont-text_hu_ca3bf91402445015.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;98&#34;
		data-flex-basis=&#34;236px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Success!&lt;/p&gt;
&lt;h2 id=&#34;advantages&#34;&gt;Advantages
&lt;/h2&gt;&lt;p&gt;Previously, I have tried generating small images from system fonts to send text to the printer. This is quite costly in terms of processing and data transfer, and the printer is unable to format or wrap the text for you.&lt;/p&gt;
&lt;p&gt;Storing glyphs in the custom font area involves transferring less raster data, and allows most text formatting commands to be used.&lt;/p&gt;
&lt;h2 id=&#34;limits&#34;&gt;Limits
&lt;/h2&gt;&lt;p&gt;These characters are a different size to the native printer fonts, so we can&amp;rsquo;t mix them on the same line. This means that we can&amp;rsquo;t use this code to implement an automatic fallback in escpos-php. However, it may appear in a future version as an alternative &amp;ldquo;PrintBuffer&amp;rdquo;, which can be explicitly enabled by developers who are not interested in using the native fonts.&lt;/p&gt;
&lt;p&gt;The &lt;a class=&#34;link&#34; href=&#34;https://github.com/receipt-print-hq/escpos-tools&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;esc2html utility&lt;/a&gt; is not able to emulate custom fonts, so the output cannot currently be rendered without an Epson printer.&lt;/p&gt;
&lt;p&gt;Also, we simply printed a stream of characters, which is not really how text works. To implement Unicode, we need to be able to join and compose characters, and respect bi-directional text. Unicode text layout is not trivial at all.&lt;/p&gt;
&lt;h2 id=&#34;get-the-code&#34;&gt;Get the code
&lt;/h2&gt;&lt;p&gt;The full script is available in the &lt;a class=&#34;link&#34; href=&#34;mike42/escpos-snippets&#34; &gt;mike42/escpos-snippets&lt;/a&gt; repo on GitHub, where I store prototypes of new functionality that is not yet ready for prime-time.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>escpos-php 2.0 released</title>
        <link>https://mike42.me/blog/2018-03-escpos-php-2-0-released</link>
        <pubDate>Tue, 13 Mar 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-03-escpos-php-2-0-released</guid>
        <description>&lt;p&gt;There is a new release of the open source receipt printing library &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;escpos-php&lt;/a&gt; available from today. For composer users, it is available as &lt;a class=&#34;link&#34; href=&#34;https://packagist.org/packages/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/escpos-php&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is the first release to drop PHP 5.3 support, which is good news for many.&lt;/p&gt;
&lt;p&gt;The &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php/releases/tag/v2.0&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;v2.0 release notes&lt;/a&gt; detail the changes and lists 10 additional printers tested out by the user base.&lt;/p&gt;
&lt;p&gt;Please direct any bug reports to &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php/issues&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;the issue tracker&lt;/a&gt; on GitHub. The &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/tag/escpos-php&#34; &gt;escpos-php&lt;/a&gt; tag on this blog has some tips and examples.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>New Wordpress theme (2018 edition)</title>
        <link>https://mike42.me/blog/2018-03-new-wordpress-theme-2018-edition</link>
        <pubDate>Thu, 08 Mar 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-03-new-wordpress-theme-2018-edition</guid>
        <description>&lt;p&gt;This week I replaced the &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2014-12-30-new-wordpress-theme&#34; &gt;previous WordPress theme&lt;/a&gt; on this blog with a new one.&lt;/p&gt;



&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-tabs-2018-03-new-wordpress-theme-2018-edition&#34;
      id=&#34;tabs-tabs-2018-03-new-wordpress-theme-2018-edition-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-tabs-2018-03-new-wordpress-theme-2018-edition-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Old theme
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2018-03-new-wordpress-theme-2018-edition/2018-03-blog-morphic.png&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2018-03-new-wordpress-theme-2018-edition/2018-03-blog-morphic_hu_ffd1a7f69de9d1dc.png 480w, https://mike42.me/blog/2018-03-new-wordpress-theme-2018-edition/2018-03-blog-morphic_hu_aebd9a112df9851d.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-tabs-2018-03-new-wordpress-theme-2018-edition&#34;
      id=&#34;tabs-tabs-2018-03-new-wordpress-theme-2018-edition-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-tabs-2018-03-new-wordpress-theme-2018-edition-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      New theme
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2018-03-new-wordpress-theme-2018-edition/2018-03-blog-new.png&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2018-03-new-wordpress-theme-2018-edition/2018-03-blog-new_hu_2251934a24eb45d7.png 480w, https://mike42.me/blog/2018-03-new-wordpress-theme-2018-edition/2018-03-blog-new_hu_7e8060e6621c8d66.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;I used &lt;a class=&#34;link&#34; href=&#34;https://getbootstrap.com/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Bootstrap&lt;/a&gt; to place widgets in my blog content, and &lt;a class=&#34;link&#34; href=&#34;http://prismjs.com/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Prism.js&lt;/a&gt; to do syntax highlighting on code snippets.&lt;/p&gt;
&lt;p&gt;This is a heavily modified version of the default &lt;a class=&#34;link&#34; href=&#34;https://en-au.wordpress.org/themes/twentyseventeen/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;twentyseventeen&lt;/a&gt; theme. I chose this as a base because of its good use of white-space for typesetting. The updated bootstrap-based layout is also a big improvement for mobile users, who now make up the majority of web traffic:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-03-new-wordpress-theme-2018-edition/Screenshot-from-2018-03-04-22-08-24.png&#34;
	width=&#34;812&#34;
	height=&#34;1363&#34;
	srcset=&#34;https://mike42.me/blog/2018-03-new-wordpress-theme-2018-edition/Screenshot-from-2018-03-04-22-08-24_hu_cdbca0db8494f954.png 480w, https://mike42.me/blog/2018-03-new-wordpress-theme-2018-edition/Screenshot-from-2018-03-04-22-08-24_hu_9cc2e7f175c5c7c4.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;59&#34;
		data-flex-basis=&#34;142px&#34;
	
&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to print custom currency symbols on a receipt printer</title>
        <link>https://mike42.me/blog/2018-03-how-to-print-custom-currency-symbols-on-a-receipt-printer</link>
        <pubDate>Thu, 01 Mar 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-03-how-to-print-custom-currency-symbols-on-a-receipt-printer</guid>
        <description>&lt;p&gt;Most receipt printers have a font that contains a &amp;lsquo;$&amp;rsquo; sign, and many have settings to print &amp;lsquo;£&amp;rsquo; &amp;lsquo;¥&amp;rsquo; and &amp;lsquo;€&amp;rsquo;. However, I don&amp;rsquo;t know of any that can display the Bitcoin &amp;lsquo;₿&amp;rsquo; or Indian Rupee &amp;lsquo;₹&amp;rsquo; symbols yet.&lt;/p&gt;
&lt;p&gt;I recently answered &lt;a href=&#34;https://github.com/mike42/escpos-php/issues/480&#34;&gt;a question&lt;/a&gt; about displaying inline images on receipts from PHP, and I think this would be the best way to output newer currency codes at the moment.&lt;/p&gt;
&lt;p&gt;Based on that answer, I used an Epson TM-T20, which understands the ESC/POS page description language, and extended the &lt;a href=&#34;https://github.com/mike42/escpos-php&#34;&gt;escpos-php&lt;/a&gt; library to list prices on a receipt in Bitcoin.&lt;/p&gt;
&lt;h2 id=&#34;option-1-use-an-inline-image&#34;&gt;Option 1: Use an inline image
&lt;/h2&gt;&lt;p&gt;Start with a 16x24 picture of your custom character. I traced the Font Awesome &lt;a href=&#34;http://fontawesome.io/icon/btc/&#34;&gt;fa-btc&lt;/a&gt; icon:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-03-how-to-print-custom-currency-symbols-on-a-receipt-printer/btc.png&#34;
	width=&#34;18&#34;
	height=&#34;24&#34;
	srcset=&#34;https://mike42.me/blog/2018-03-how-to-print-custom-currency-symbols-on-a-receipt-printer/btc_hu_b5f799c84809a787.png 480w, https://mike42.me/blog/2018-03-how-to-print-custom-currency-symbols-on-a-receipt-printer/btc_hu_b4dea2cd12eac8a0.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;75&#34;
		data-flex-basis=&#34;180px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I then extended escpos-php to issue the &lt;tt&gt;ESC *&lt;/tt&gt; command without breaking the line, and injected this picture like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\EscposImage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;CustomPrinter&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;extends&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Print image inline. If it is a multi-line image, then only the first line is printed!
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;inlineImage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;EscposImage&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$img&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;IMG_DEFAULT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$highDensityVertical&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;IMG_DOUBLE_HEIGHT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;IMG_DOUBLE_HEIGHT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$highDensityHorizontal&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;IMG_DOUBLE_WIDTH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;IMG_DOUBLE_WIDTH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// Header and density code (0, 1, 32, 33) re-used for every line
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nv&#34;&gt;$densityCode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$highDensityHorizontal&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$highDensityVertical&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;32&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$colFormatData&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$img&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;toColumnFormat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$highDensityVertical&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$header&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;dataHeader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$img&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;getWidth&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()),&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$colFormatData&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;c1&#34;&gt;// Print each line, double density etc for printing are set here also
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;            &lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;ESC&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$densityCode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$header&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Fill in your own connector here */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;php://stdout&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;CustomPrinter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$btc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;EscposImage&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;load&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;btc.png&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Item    &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;inlineImage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$btc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;2.50&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The result was:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-03-how-to-print-custom-currency-symbols-on-a-receipt-printer/2018-02-btc.png&#34;
	width=&#34;2295&#34;
	height=&#34;213&#34;
	srcset=&#34;https://mike42.me/blog/2018-03-how-to-print-custom-currency-symbols-on-a-receipt-printer/2018-02-btc_hu_98f14ee9fc73dae8.png 480w, https://mike42.me/blog/2018-03-how-to-print-custom-currency-symbols-on-a-receipt-printer/2018-02-btc_hu_bfb628d41e00308a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;1077&#34;
		data-flex-basis=&#34;2585px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;If you just have a few custom character to print, then this clearly works. Unfortunately, you can&amp;rsquo;t use text formatting commands alongside this method.&lt;/p&gt;
&lt;h2 id=&#34;option-2-use-a-custom-character-set&#34;&gt;Option 2: Use a custom character set
&lt;/h2&gt;&lt;p&gt;This is a more complex method, where we will instruct the printer to use a BTC symbol in place of a dollar sign, through a custom character.&lt;/p&gt;
&lt;p&gt;You must use a 12x24 image for this method, which is the standard size of the receipt printer font for most Epson models:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-03-how-to-print-custom-currency-symbols-on-a-receipt-printer/2018-03-btc2.png&#34;
	width=&#34;12&#34;
	height=&#34;24&#34;
	srcset=&#34;https://mike42.me/blog/2018-03-how-to-print-custom-currency-symbols-on-a-receipt-printer/2018-03-btc2_hu_4be69278956ae31e.png 480w, https://mike42.me/blog/2018-03-how-to-print-custom-currency-symbols-on-a-receipt-printer/2018-03-btc2_hu_9c4565d0c31bbc2a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;50&#34;
		data-flex-basis=&#34;120px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The example code now changes to include the &lt;code&gt;ESC %&lt;/code&gt; and &lt;code&gt;ESC %&lt;/code&gt; commands:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\EscposImage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;MyCoolPrinter&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;extends&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;setUserDefinedCharacter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;EscposImage&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$img&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$char&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$verticalBytes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$colFormatData&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$img&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;toColumnFormat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$colFormatData&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;c1&#34;&gt;// Print each line, double density etc for printing are set here also
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;            &lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;ESC&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;amp;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$verticalBytes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$img&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;getWidth&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;selectUserDefinedCharacterSet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$on&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;validateBoolean&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__FUNCTION__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;ESC&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;%&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$on&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Fill in your own connector here */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;php://stdout&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;MyCoolPrinter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Replace &amp;#39;$&amp;#39; with a 24x12 image.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;EscposImage&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;load&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;btc2.png&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setUserDefinedCharacter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$char&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;$&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectUserDefinedCharacterSet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Print some stuff normally
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Item    $2.50&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Which produces this output:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-03-how-to-print-custom-currency-symbols-on-a-receipt-printer/2018-03-btcoutput1.png&#34;
	width=&#34;1024&#34;
	height=&#34;79&#34;
	srcset=&#34;https://mike42.me/blog/2018-03-how-to-print-custom-currency-symbols-on-a-receipt-printer/2018-03-btcoutput1_hu_c2bc6d2d0bf3a7dc.png 480w, https://mike42.me/blog/2018-03-how-to-print-custom-currency-symbols-on-a-receipt-printer/2018-03-btcoutput1_hu_700f4bb8b482ecd4.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;1296&#34;
		data-flex-basis=&#34;3110px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The difference here is that you can also apply text formatting commands to these characters, such as double-height or emphasis:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// ... Add to the end of the previous example
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Print some stuff normally
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Item    $2.50&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Go taller!
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectPrintMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;MODE_DOUBLE_HEIGHT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Item    $2.50&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Emphasis too?
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectPrintMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;MODE_DOUBLE_HEIGHT&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;MODE_EMPHASIZED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Item    $2.50&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Adjust height and width
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setTextSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;$&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-03-how-to-print-custom-currency-symbols-on-a-receipt-printer/2018-03-btcoutput2.png&#34;
	width=&#34;1024&#34;
	height=&#34;609&#34;
	srcset=&#34;https://mike42.me/blog/2018-03-how-to-print-custom-currency-symbols-on-a-receipt-printer/2018-03-btcoutput2_hu_c26b00967d27feb0.png 480w, https://mike42.me/blog/2018-03-how-to-print-custom-currency-symbols-on-a-receipt-printer/2018-03-btcoutput2_hu_8d4054de31aa3a63.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;168&#34;
		data-flex-basis=&#34;403px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Both of these methods let us encode arbitrary characters that we couldn&amp;rsquo;t otherwise be able to print. All we need is bitmaps for each character.&lt;/p&gt;
&lt;p&gt;There is no plan to include bitmap fonts with &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;escpos-php&lt;/a&gt; at the moment, but this basic mechanism might be used to improve Unicode support for a lot of receipt printers in the future.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 2018-03-11&lt;/strong&gt;: I added the custom character set option to this post.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to use HiDPI displays on Debian 9</title>
        <link>https://mike42.me/blog/2018-02-how-to-use-hidpi-displays-on-debian-9</link>
        <pubDate>Thu, 22 Feb 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-02-how-to-use-hidpi-displays-on-debian-9</guid>
        <description>&lt;p&gt;I recently added a 4K monitor to my Debian box, and had to set a few things to make it display things at a good size. These high-density monitors that are becoming common on laptops and desktops are known as &amp;ldquo;HiDPI&amp;rdquo; displays.&lt;/p&gt;
&lt;p&gt;Currently I get the best results with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Window scaling factor of 2&lt;/li&gt;
&lt;li&gt;Font scaling 0.90 to make text slightly smaller&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that &amp;ldquo;window scaling&amp;rdquo; is not &amp;ldquo;upscaling&amp;rdquo; (stretching an image). In this version of Gnome, it means &amp;ldquo;single/double/triple DPI&amp;rdquo;. The implementations are in the process of changing: Soon you should be able to set any scaling factor.&lt;/p&gt;
&lt;p&gt;This post assumes a Gnome version around 3.26, which is what you would get as a default if you installed Debian 9 today.&lt;/p&gt;
&lt;h2 id=&#34;apply-to-one-user-only&#34;&gt;Apply to one user only
&lt;/h2&gt;&lt;p&gt;Under &lt;strong&gt;Settings → Devices → Displays&lt;/strong&gt; set the &lt;strong&gt;Scale&lt;/strong&gt; to &lt;strong&gt;200%&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-02-how-to-use-hidpi-displays-on-debian-9/2018-01-dpi02.png&#34;
	width=&#34;1960&#34;
	height=&#34;1374&#34;
	srcset=&#34;https://mike42.me/blog/2018-02-how-to-use-hidpi-displays-on-debian-9/2018-01-dpi02_hu_baf871a217633d1c.png 480w, https://mike42.me/blog/2018-02-how-to-use-hidpi-displays-on-debian-9/2018-01-dpi02_hu_dfb44d3b797d3512.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;142&#34;
		data-flex-basis=&#34;342px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Under &lt;strong&gt;Tweaks → Fonts&lt;/strong&gt;, set the &lt;strong&gt;Scaling Factor&lt;/strong&gt; to &lt;strong&gt;0.90&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-02-how-to-use-hidpi-displays-on-debian-9/2018-01-dpi01.png&#34;
	width=&#34;1796&#34;
	height=&#34;1316&#34;
	srcset=&#34;https://mike42.me/blog/2018-02-how-to-use-hidpi-displays-on-debian-9/2018-01-dpi01_hu_952b355118808401.png 480w, https://mike42.me/blog/2018-02-how-to-use-hidpi-displays-on-debian-9/2018-01-dpi01_hu_988bb31b8c66b122.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;136&#34;
		data-flex-basis=&#34;327px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Next, add these variables to &lt;code&gt;~/bashrc&lt;/code&gt; to apply similar scaling to QT apps.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;QT_AUTO_SCREEN_SCALE_FACTOR=0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;QT_SCALE_FACTOR=2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Log out and back in to ensure that the settings have applied everywhere.&lt;/p&gt;
&lt;h2 id=&#34;apply-to-all-users&#34;&gt;Apply to all users
&lt;/h2&gt;&lt;p&gt;If you have a shared system (eg. domain accounts), or want to style the login box as well, then you can set the same settings as below.&lt;/p&gt;
&lt;p&gt;These steps are based on answers to the Ask Ubuntu question: &lt;a class=&#34;link&#34; href=&#34;https://askubuntu.com/questions/469515/adjust-text-scaling-factor-for-all-users&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Adjust text scaling factor for all users&amp;lt;&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nano /usr/share/glib-2.0/schemas/org.gnome.desktop.interface.gschema.xml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Set the &lt;code&gt;text-scaling-factor&lt;/code&gt; to &lt;code&gt;0.9&lt;/code&gt;, and the &lt;code&gt;scaling-factor&lt;/code&gt; to &lt;code&gt;2&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;&amp;lt;key&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;name=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;text-scaling-factor&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;range&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;min=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;0.5&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;max=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;3.0&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;default&amp;gt;&lt;/span&gt;0.9&lt;span class=&#34;nt&#34;&gt;&amp;lt;/default&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;Text scaling factor&lt;span class=&#34;nt&#34;&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;description&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    Factor used to enlarge or reduce text display, without changing font si$
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;&amp;lt;key&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;name=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;scaling-factor&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;u&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;default&amp;gt;&lt;/span&gt;2&lt;span class=&#34;nt&#34;&gt;&amp;lt;/default&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;Window scaling factor&lt;span class=&#34;nt&#34;&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;description&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    Integer factor used to scale windows by. For use on high-dpi screens.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    0 means pick automatically based on monitor.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Re-compile the schemas:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;glib-compile-schemas /usr/share/glib-2.0/schemas
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next drop some similar environment variables for QT apps in &lt;code&gt;/etc/profile.d/hidpi.sh&lt;/code&gt; to apply it to all users:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;QT_AUTO_SCREEN_SCALE_FACTOR&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;QT_SCALE_FACTOR&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After this, reboot. If the setting has applied, then the &lt;code&gt;gdm3&lt;/code&gt; login box will be scaled as well.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to print Spanish characters on a thermal receipt printer</title>
        <link>https://mike42.me/blog/2018-02-how-to-print-spanish-characters-on-a-thermal-receipt-printer</link>
        <pubDate>Thu, 15 Feb 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-02-how-to-print-spanish-characters-on-a-thermal-receipt-printer</guid>
        <description>&lt;p&gt;Today we&amp;rsquo;re going to send some Spanish text to an Epson TM-T20 thermal receipt printer. This post is intended for people who know how to send ASCII to a similar printer, but can&amp;rsquo;t get the diacritics from Spanish to displayu properly, characters like á, é, í, ó, ñ, ú or ü.&lt;/p&gt;
&lt;p&gt;Many receipt printers understand a language called ESC/POS, which uses legacy &lt;a href=&#34;https://en.wikipedia.org/wiki/Code_page&#34;&gt;code pages&lt;/a&gt; for non-ASCII text.&lt;/p&gt;
&lt;p&gt;Spanish is very easy to encode manually, because it can be represented fully using just &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Code_page_437&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Code Page 437&lt;/a&gt;, which happens to be the default code page on most receipt printers.&lt;/p&gt;
&lt;h2 id=&#34;generating-cp437-encoded-text&#34;&gt;Generating CP437-encoded text
&lt;/h2&gt;&lt;p&gt;To convert UTF-8 to CP437, I will use the &lt;code&gt;iconv&lt;/code&gt; utility on the Linux command-line. API&amp;rsquo;s for encoding conversion are available for your favourite programming language:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;echo &amp;#34;áéíóñúü&amp;#34; | iconv --from-code=UTF-8 --to-code=CP437
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-02-how-to-print-spanish-characters-on-a-thermal-receipt-printer/2018-02-text01.png&#34;
	width=&#34;940&#34;
	height=&#34;70&#34;
	srcset=&#34;https://mike42.me/blog/2018-02-how-to-print-spanish-characters-on-a-thermal-receipt-printer/2018-02-text01_hu_c3a4a7d1ddc31eb.png 480w, https://mike42.me/blog/2018-02-how-to-print-spanish-characters-on-a-thermal-receipt-printer/2018-02-text01_hu_86a582af1fcde198.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;1342&#34;
		data-flex-basis=&#34;3222px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Or, as a more complete example, let&amp;rsquo;s use a pangram from &lt;a class=&#34;link&#34; href=&#34;http://clagnut.com/blog/2380/#Spanish&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;here&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Benjamín pidió una bebida de kiwi y fresa; Noé, sin vergüenza, la más exquisita champaña del menú&amp;rdquo;&lt;/p&gt;&lt;/blockquote&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Benjamín pidió una bebida de kiwi y fresa; \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;Noé, sin vergüenza, la más exquisita champaña del menú&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;iconv --from-code&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;UTF-8 --to-code&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;CP437
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-02-how-to-print-spanish-characters-on-a-thermal-receipt-printer/2018-02-text02.png&#34;
	width=&#34;990&#34;
	height=&#34;176&#34;
	srcset=&#34;https://mike42.me/blog/2018-02-how-to-print-spanish-characters-on-a-thermal-receipt-printer/2018-02-text02_hu_f74610ce3423796e.png 480w, https://mike42.me/blog/2018-02-how-to-print-spanish-characters-on-a-thermal-receipt-printer/2018-02-text02_hu_7b6f56ff9c5d9a26.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;562&#34;
		data-flex-basis=&#34;1350px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;printing-the-text&#34;&gt;Printing the text
&lt;/h2&gt;&lt;p&gt;Next, let&amp;rsquo;s send some text to the printer. I have &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2015-03-getting-a-usb-receipt-printer-working-on-linux&#34; &gt;a USB printer on Linux&lt;/a&gt;, and this is how I would send it data:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;echo &amp;#34;Hello World&amp;#34; &amp;gt; /dev/usb/lp0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-02-how-to-print-spanish-characters-on-a-thermal-receipt-printer/2018-02-text03.jpg&#34;
	width=&#34;1024&#34;
	height=&#34;104&#34;
	srcset=&#34;https://mike42.me/blog/2018-02-how-to-print-spanish-characters-on-a-thermal-receipt-printer/2018-02-text03_hu_19dd9802d2e89065.jpg 480w, https://mike42.me/blog/2018-02-how-to-print-spanish-characters-on-a-thermal-receipt-printer/2018-02-text03_hu_1ccdc71e5b733be9.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;984&#34;
		data-flex-basis=&#34;2363px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Putting it all together.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Benjamín pidió una bebida de kiwi y fresa; \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;Noé, sin vergüenza, la más exquisita champaña del menú&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;iconv --from-code&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;UTF-8 --to-code&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;CP437 &amp;gt; /dev/usb/lp0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This now displays the diacritics correctly when printed.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-02-how-to-print-spanish-characters-on-a-thermal-receipt-printer/2018-02-text04.jpg&#34;
	width=&#34;1024&#34;
	height=&#34;195&#34;
	srcset=&#34;https://mike42.me/blog/2018-02-how-to-print-spanish-characters-on-a-thermal-receipt-printer/2018-02-text04_hu_c82e1525a9f2f2c4.jpg 480w, https://mike42.me/blog/2018-02-how-to-print-spanish-characters-on-a-thermal-receipt-printer/2018-02-text04_hu_4884fcfccd80358d.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;525&#34;
		data-flex-basis=&#34;1260px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;libraries-for-php-and-python-users&#34;&gt;Libraries for PHP and Python users
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;ve helped out writing the internationalization features for two printing libraries (&lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;escpos-php&lt;/a&gt; and &lt;a class=&#34;link&#34; href=&#34;https://github.com/python-escpos/python-escpos&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;python-escpos&lt;/a&gt;, so that programmers can work with text in UTF-8, and let the library translate the text to something that your printer understand.&lt;/p&gt;
&lt;p&gt;The same example above, if you use the PHP library, would look like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/vendor/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Benjamín pidió una bebida de kiwi y fresa; Noé, sin vergüenza, la más exquisita champaña del menú&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And in Python, it would look like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;escpos&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;my_printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;File&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;my_printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Benjamín pidió una bebida de kiwi y fresa; Noé, sin vergüenza, la más exquisita champaña del menú&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;my_printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Most of the time you need more than text: Formatting, adding barcodes, or cutting the paper will all need ESC/POS commands, and these libraries will help with that too.&lt;/p&gt;
&lt;p&gt;Take a look at the project links for more detail.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to install PHP Composer as a regular user</title>
        <link>https://mike42.me/blog/2018-02-how-to-install-php-composer-as-a-regular-user</link>
        <pubDate>Thu, 08 Feb 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-02-how-to-install-php-composer-as-a-regular-user</guid>
        <description>&lt;p&gt;Composer is an essential utility for PHP programmers, and allows you to manage dependencies.&lt;/p&gt;
&lt;h2 id=&#34;dependencies&#34;&gt;Dependencies
&lt;/h2&gt;&lt;p&gt;You can use your regular account to install composer, use it, and even update it. You do need to have a few packages installed first though:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install git curl php-cli
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or on Fedora:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo dnf install git curl php-cli
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;local-install&#34;&gt;Local install
&lt;/h2&gt;&lt;p&gt;Next, fetch the installer and deploy composer to your home directory&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;curl https://getcomposer.org/installer &amp;gt; composer-setup.php
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir -p ~/.local/bin
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;php composer-setup.php --install-dir=$HOME/.local/bin --filename=composer
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rm composer-setup.php
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Last, add &lt;code&gt;~/.local/bin&lt;/code&gt; to your &lt;code&gt;$PATH&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;echo &amp;#39;PATH=$PATH:~/.local/bin&amp;#39; &amp;gt;&amp;gt; ~/.bashrc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;source  ~/.bashrc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;echo $PATH
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can now run composer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ composer --help
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Usage:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  help [options] [--] [&amp;lt;command_name&amp;gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ composer self-update
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;You are already using composer version 1.5.6 (stable channel).
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;make-composer-available-for-all-users&#34;&gt;Make Composer available for all users
&lt;/h2&gt;&lt;p&gt;Just run this line if you decide that all users should have access to your copy of Composer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo mv ~/.local/bin/composer /usr/local/bin/composer
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you look up a how to install Composer, you will find a tempting one-liner that uses &lt;code&gt;curl&lt;/code&gt; to fetch a script from the Composer website, then executes it as &lt;code&gt;root&lt;/code&gt;. I don&amp;rsquo;t think it&amp;rsquo;s good practice to install software like that, so I would encourage you to just run &amp;lsquo;sudo mv&amp;rsquo; at the end.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to boot Debian in 4 seconds</title>
        <link>https://mike42.me/blog/2018-02-how-to-boot-debian-in-4-seconds</link>
        <pubDate>Thu, 01 Feb 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-02-how-to-boot-debian-in-4-seconds</guid>
        <description>&lt;p&gt;This blog post is a throwback to &amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;https://web.archive.org/web/20201023004224/https://debian-administration.org/article/620/Booting_Debian_in_14_seconds&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Booting Debian in 14 seconds&lt;/a&gt;&amp;rdquo; from debian-administration.org, where the author went through some fairly advanced steps to get his low-spec Debian laptop to boot quickly. Debian was version 4.0 at the time, and I recall it taking around 40 seconds to boot on a default desktop install.&lt;/p&gt;
&lt;p&gt;In a rare exception to &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Wirth%27s_law&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Wirth&amp;rsquo;s law&lt;/a&gt;, waiting for a computer to boot is no longer &amp;ldquo;a thing&amp;rdquo;. A default desktop install of Debian includes systemd, and uses a multicore CPU and SSD quite efficiently. Also, sleep/wake works more reliably than it used to, so boot speed is not as important as it used to be.&lt;/p&gt;
&lt;p&gt;On a modern desktop PC, booting Debian 9 (default desktop install) takes me 14 seconds with no extra configuration, so that&amp;rsquo;s our new low water mark.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-02-how-to-boot-debian-in-4-seconds/2018-01-boot01.png&#34;
	width=&#34;1460&#34;
	height=&#34;200&#34;
	srcset=&#34;https://mike42.me/blog/2018-02-how-to-boot-debian-in-4-seconds/2018-01-boot01_hu_60d11740bd98fed1.png 480w, https://mike42.me/blog/2018-02-how-to-boot-debian-in-4-seconds/2018-01-boot01_hu_5de876099c8325e2.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;730&#34;
		data-flex-basis=&#34;1752px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Mainly to illustrate how far open source operating systems have come, I&amp;rsquo;m going to step through a boot process speed-up, the way it looks in 2018.&lt;/p&gt;
&lt;h2 id=&#34;summary&#34;&gt;Summary
&lt;/h2&gt;&lt;h3 id=&#34;out&#34;&gt;Out
&lt;/h3&gt;&lt;p&gt;You will read about some of these older tricks if you search for Linux Boot speed, and they are all quite irrelevant in 2018, in my humble opinion-&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Swapping the &lt;code&gt;/bin/sh&lt;/code&gt; shell to &lt;code&gt;dash&lt;/code&gt; - it is already the default, but also init scripts are no longer used.&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;readahead&lt;/code&gt; - gains are marginal unless you have a HDD.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;&lt;code&gt;noatime&lt;/code&gt;&amp;rdquo; setting on mounts - &amp;ldquo;&lt;code&gt;relatime&lt;/code&gt;&amp;rdquo; is a default mount option since Linux 2.6.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;in&#34;&gt;In
&lt;/h3&gt;&lt;p&gt;New things that you won&amp;rsquo;t find in pre-systemd guides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;systemd-analyze&lt;/code&gt; to instrument the boot&lt;/li&gt;
&lt;li&gt;&lt;code&gt;systemctl&lt;/code&gt; to exclude processes from boot&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;still-relevant&#34;&gt;Still relevant
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bootchart&lt;/code&gt; is still useful for drawing pretty graphs&lt;/li&gt;
&lt;li&gt;Configure GRUB &amp;amp; UEFI not to prompt for input&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t enable services you don&amp;rsquo;t need&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;process&#34;&gt;Process
&lt;/h2&gt;&lt;h3 id=&#34;remove-bootloader-delay&#34;&gt;Remove bootloader delay
&lt;/h3&gt;&lt;p&gt;Between UEFI and the OS, you will get the bootloader, which will wait for 5 seconds by default to see if you want to select a different item. Start by switching the &lt;code&gt;grub&lt;/code&gt; timeout from 5 seconds to 0.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo nano /etc/default/grub
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Set &lt;code&gt;GRUB_TIMEOUT=0&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-02-how-to-boot-debian-in-4-seconds/Screenshot-from-2017-12-29-11-34-46.png&#34;
	width=&#34;1308&#34;
	height=&#34;944&#34;
	srcset=&#34;https://mike42.me/blog/2018-02-how-to-boot-debian-in-4-seconds/Screenshot-from-2017-12-29-11-34-46_hu_28c1e028fc2e55d4.png 480w, https://mike42.me/blog/2018-02-how-to-boot-debian-in-4-seconds/Screenshot-from-2017-12-29-11-34-46_hu_36e21a06cf44a2bf.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;138&#34;
		data-flex-basis=&#34;332px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Apply the grub configuration change:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo update-grub2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;look-at-systemd&#34;&gt;Look at systemd
&lt;/h3&gt;&lt;p&gt;Use the tool &lt;code&gt;systemd-analyze&lt;/code&gt; to draw a picture:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;systemd-analyze plot &amp;gt; plot.svg
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In my case, it was clear that 9 seconds of the boot was an optional &amp;ldquo;waiting for network&amp;rdquo; step.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-02-how-to-boot-debian-in-4-seconds/2018-01-boot02.png&#34;
	width=&#34;1460&#34;
	height=&#34;98&#34;
	srcset=&#34;https://mike42.me/blog/2018-02-how-to-boot-debian-in-4-seconds/2018-01-boot02_hu_88e0b3f8744a58d1.png 480w, https://mike42.me/blog/2018-02-how-to-boot-debian-in-4-seconds/2018-01-boot02_hu_5385fa9114c3cc00.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;1489&#34;
		data-flex-basis=&#34;3575px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;So, (&lt;a class=&#34;link&#34; href=&#34;https://askubuntu.com/questions/615006/ubuntu-15-04-network-manager-causing-slow-boot&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;thank you askubuntu&lt;/a&gt;), I disabled that service and rebooted:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo systemctl disable NetworkManager-wait-online.service
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Removed /etc/systemd/system/network-online.target.wants/NetworkManager-wait-online.service.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I then ran &lt;code&gt;systemd-analyze&lt;/code&gt; again, and found that the boot was still taking 4.4 seconds, so, more analysis was in order:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-02-how-to-boot-debian-in-4-seconds/2018-01-boot03.png&#34;
	width=&#34;1093&#34;
	height=&#34;181&#34;
	srcset=&#34;https://mike42.me/blog/2018-02-how-to-boot-debian-in-4-seconds/2018-01-boot03_hu_cb5c4118fa847826.png 480w, https://mike42.me/blog/2018-02-how-to-boot-debian-in-4-seconds/2018-01-boot03_hu_79618eef5bd83539.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;603&#34;
		data-flex-basis=&#34;1449px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;systemd-timesyncd&lt;/code&gt; service was holding things up.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-02-how-to-boot-debian-in-4-seconds/2018-01-boot04.png&#34;
	width=&#34;1093&#34;
	height=&#34;124&#34;
	srcset=&#34;https://mike42.me/blog/2018-02-how-to-boot-debian-in-4-seconds/2018-01-boot04_hu_57116628d65aa27e.png 480w, https://mike42.me/blog/2018-02-how-to-boot-debian-in-4-seconds/2018-01-boot04_hu_d49d046f2fee2c8a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;881&#34;
		data-flex-basis=&#34;2115px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This service runs early in the boot process, reads an old time from a file, and tries to update time over the network. Since I have a working RTC, this is all unnecessary for me, so I removed it and replaced it with &lt;code&gt;chronyd&lt;/code&gt;, which is happy to operate in the background.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo systemctl disable systemd-timesyncd.service
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install chronyd
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo systemctl &lt;span class=&#34;nb&#34;&gt;enable&lt;/span&gt; chrony
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After another reboot:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;systemd-analyze plot &amp;gt; plot4.svg
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There we go, down to 4.096 seconds with a few minutes of effort. I think that&amp;rsquo;s acceptable.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-02-how-to-boot-debian-in-4-seconds/2018-01-boot05.png&#34;
	width=&#34;1092&#34;
	height=&#34;180&#34;
	srcset=&#34;https://mike42.me/blog/2018-02-how-to-boot-debian-in-4-seconds/2018-01-boot05_hu_216bffdcd6fb96db.png 480w, https://mike42.me/blog/2018-02-how-to-boot-debian-in-4-seconds/2018-01-boot05_hu_8e06eafcd411a2eb.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;606&#34;
		data-flex-basis=&#34;1456px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The systemd developers &lt;a class=&#34;link&#34; href=&#34;https://freedesktop.org/wiki/Software/systemd/Optimizations/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;are quite certain that you can boot in under 2 seconds&lt;/a&gt;, but I wasn&amp;rsquo;t willing to customise my system to that extent.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to use parallel to speed up your work</title>
        <link>https://mike42.me/blog/2018-01-how-to-use-parallel-to-speed-up-your-work</link>
        <pubDate>Thu, 25 Jan 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-01-how-to-use-parallel-to-speed-up-your-work</guid>
        <description>&lt;p&gt;GNU Parallel is a tool to execute multiple commands at once. In its basic usage, you would list your commands in a file, so that it can execute them, several at a time.&lt;/p&gt;
&lt;p&gt;It gives the most benefit on processes that don&amp;rsquo;t fully utilise your CPU. Almost every laptop, desktop and single board computer now has multiple CPU cores available, so you are probably missing out if you frequently perform batch operations without it.&lt;/p&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation
&lt;/h2&gt;&lt;p&gt;On Debian or Ubuntu:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install parallel
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;parallel --cite
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On Fedora the package name is the same:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo dnf install parallel
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;parallel --cite
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;example-1-convert-loops-to-pipes&#34;&gt;Example 1: Convert loops to pipes
&lt;/h2&gt;&lt;p&gt;Using the ImageMagick tool to convert a folder of GIF images to PNG format can be done in a loop:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;for i in *.gif; do convert $i -scale 200% ${i%.*}.png; done
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or, you could print each command in a loop then pass them to parallel.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;for i in *.gif; do echo convert $i -scale 200% ${i%.*}.png; done | parallel
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The second command is many times faster on a multicore computer.&lt;/p&gt;
&lt;h2 id=&#34;example-2-replace-xargs-with-parallel&#34;&gt;Example 2: Replace xargs with parallel
&lt;/h2&gt;&lt;p&gt;This command executes a single &amp;ldquo;pngcrush&amp;rdquo; command on each PNG file in a directory, one at a time.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find . -type f -name &amp;#39;*.png&amp;#39; -print0  | xargs -0 -n1 -r pngcrush -q -ow -brute
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To convert this to use parallel, you would use the following command-line:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find . -type f -name &amp;#39;*.png&amp;#39; | parallel &amp;#34;pngcrush -q -ow -brute {}&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;dont-use-xargs-in-parallel-mode&#34;&gt;Don&amp;rsquo;t use xargs in parallel mode
&lt;/h2&gt;&lt;p&gt;Expert command line users will also know about &lt;code&gt;xargs -P&lt;/code&gt;, which seems to do the same thing at a glance.&lt;/p&gt;
&lt;p&gt;xargs is good at making really long command-lines, and not so good at executing multiple commands at once. It will mix the output of the commands, and requires you to specify the number of jobs to run.&lt;/p&gt;
&lt;p&gt;Parallel is designed to do lots of things at once, and it does it well. It will choose some good defaults for the number of processes to execute, and adds an insane collection of features that you need for large batches. To name just a few:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Control spawning of new jobs based on things like available memory, system load, or an absolute number of jobs to keep running&lt;/li&gt;
&lt;li&gt;Distribute jobs to remote computers&lt;/li&gt;
&lt;li&gt;Show progress&lt;/li&gt;
&lt;li&gt;Control of when to terminate the jobs&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>How to generate star fields</title>
        <link>https://mike42.me/blog/2018-01-howo-to-generate-star-fields</link>
        <pubDate>Thu, 18 Jan 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-01-howo-to-generate-star-fields</guid>
        <description>&lt;p&gt;I recently needed a texture for the &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Skybox_%28video_games%29&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;skybox&lt;/a&gt; in a 3D space game.&lt;/p&gt;
&lt;p&gt;I used this ImageMagick one-liner to generate a dotted canvas with some grey and white pixels. It displays well if the texture will be stretched.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;convert -size 1600x900 xc: +noise Random -channel R -threshold 0.5% &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -negate -channel RG -separate +channel &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -compose multiply -composite stars.png
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars.png&#34;
	width=&#34;1600&#34;
	height=&#34;900&#34;
	srcset=&#34;https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars_hu_690988c24801cf4c.png 480w, https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars_hu_f94f43f9cafce7d5.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;alternative-style&#34;&gt;Alternative style
&lt;/h2&gt;&lt;p&gt;With a simple modification, the bright stars are made bigger, and the dull ones are made smaller, with only black and white used. This works well if the texture will be shrunk for display.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;convert -size 800x450 xc: +noise Random -channel R -threshold 0.5% &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -negate -channel RG -separate +channel &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -compose multiply -composite -resize 200% &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;        -threshold 10% stars-rounded.png
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-rounded.png&#34;
	width=&#34;1600&#34;
	height=&#34;900&#34;
	srcset=&#34;https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-rounded_hu_74b4260d6edbd9ff.png 480w, https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-rounded_hu_5e7a56bad801406d.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;full-process&#34;&gt;Full process
&lt;/h2&gt;&lt;p&gt;Although these are great one-liners, the actual process is a bit hard to follow without some smaller steps.&lt;/p&gt;
&lt;p&gt;Here, I&amp;rsquo;ll walk through how to generate a 150x90 star field in several steps. I&amp;rsquo;ve scaled each of these pictures to 200% of their original size and converted them to PNG for display on the web. I&amp;rsquo;ve used BMP in the commands only because it saves some plumbing around colour spaces.&lt;/p&gt;
&lt;p&gt;Start with a blank &lt;a class=&#34;link&#34; href=&#34;http://www.imagemagick.org/Usage/canvas/%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;canvas&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;convert -size 150x90 xc: stars-01.bmp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-01.png&#34;
	width=&#34;300&#34;
	height=&#34;180&#34;
	srcset=&#34;https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-01_hu_509983ebe9cff4dd.png 480w, https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-01_hu_213159ef817ac43a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;166&#34;
		data-flex-basis=&#34;400px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Add random RGB noise:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;convert stars-01.bmp +noise Random stars-02.bmp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-02.png&#34;
	width=&#34;300&#34;
	height=&#34;180&#34;
	srcset=&#34;https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-02_hu_4c5b5999185f690c.png 480w, https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-02_hu_ee847a126dbcdef5.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;166&#34;
		data-flex-basis=&#34;400px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;In the &lt;strong&gt;red channel&lt;/strong&gt; of the image, apply a black/white threshold: If the red channel is greater than 0.5%, it is set to the maximum, otherwise it is set to the minimum.&lt;/p&gt;
&lt;p&gt;Mostly the &lt;strong&gt;red channel&lt;/strong&gt; is now 100%, with random dots of 0%. The &lt;strong&gt;blue and green channels&lt;/strong&gt; are still completely random:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;convert stars-02.bmp -channel R -threshold 0.5% stars-03.bmp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-03.png&#34;
	width=&#34;300&#34;
	height=&#34;180&#34;
	srcset=&#34;https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-03_hu_e8d97033af53afd0.png 480w, https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-03_hu_8cd2730af17f2f23.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;166&#34;
		data-flex-basis=&#34;400px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Negate the image, so that the &lt;strong&gt;red channel&lt;/strong&gt; is mostly 0%, with dots of 100%:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;convert stars-03.bmp -negate stars-04.bmp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-04.png&#34;
	width=&#34;300&#34;
	height=&#34;180&#34;
	srcset=&#34;https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-04_hu_8c8ea10df86e9e9e.png 480w, https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-04_hu_47a951f3ad6616ab.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;166&#34;
		data-flex-basis=&#34;400px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Extract the &lt;strong&gt;red channel&lt;/strong&gt; and &lt;strong&gt;green channel&lt;/strong&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;convert stars-04.bmp -channel RG -separate +channel stars-05.bmp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;strong&gt;red channel&lt;/strong&gt; will be dots of white:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-05-0.png&#34;
	width=&#34;300&#34;
	height=&#34;180&#34;
	srcset=&#34;https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-05-0_hu_9a9569a23e6f546e.png 480w, https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-05-0_hu_9c63e7cfa9c023a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;166&#34;
		data-flex-basis=&#34;400px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;green channel&lt;/strong&gt; will be random:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-05-1.png&#34;
	width=&#34;300&#34;
	height=&#34;180&#34;
	srcset=&#34;https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-05-1_hu_d8f779ac80df7ad8.png 480w, https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-05-1_hu_ed477acfb12272b1.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;166&#34;
		data-flex-basis=&#34;400px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Multiply the channels together, so that the white dots become grey dots, each with a random brightness:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;convert stars-05-0.bmp stars-05-1.bmp -compose multiply -composite stars-06.bmp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-06.png&#34;
	width=&#34;300&#34;
	height=&#34;180&#34;
	srcset=&#34;https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-06_hu_26e0de602e85f0cb.png 480w, https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-06_hu_f9de0b74c138e6d2.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;166&#34;
		data-flex-basis=&#34;400px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;For the alternative style, scale the image up, then apply a new threshold. Brighter dots will appear as larger patches of white, while dull stars will be smaller or invisible:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;convert stars-06.bmp -resize 200% -threshold 10% stars-06-rounded.bmp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-06-rounded.png&#34;
	width=&#34;300&#34;
	height=&#34;180&#34;
	srcset=&#34;https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-06-rounded_hu_e117dad796dc16ce.png 480w, https://mike42.me/blog/2018-01-howo-to-generate-star-fields/stars-06-rounded_hu_baaf8c76033a8985.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;166&#34;
		data-flex-basis=&#34;400px&#34;
	
&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>On running deployments via GitHub</title>
        <link>https://mike42.me/blog/2018-01-on-running-deployments-via-github</link>
        <pubDate>Wed, 10 Jan 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-01-on-running-deployments-via-github</guid>
        <description>&lt;p&gt;&lt;strong&gt;TL;DR;&lt;/strong&gt; - GitHub can be pretty unreliable, depend on it at your peril.&lt;/p&gt;
&lt;p&gt;GitHub was down for about 20 minutes today. I happened to be logged in, so I&amp;rsquo;ll share a few screen captures.&lt;/p&gt;
&lt;h2 id=&#34;what-a-github-outage-looks-like&#34;&gt;What a GitHub outage looks like
&lt;/h2&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-01-on-running-deployments-via-github/2018-01-10-20-59-49-github.png&#34;
	width=&#34;1884&#34;
	height=&#34;1404&#34;
	srcset=&#34;https://mike42.me/blog/2018-01-on-running-deployments-via-github/2018-01-10-20-59-49-github_hu_f8da40a6494a1897.png 480w, https://mike42.me/blog/2018-01-on-running-deployments-via-github/2018-01-10-20-59-49-github_hu_1db77a5b6ea85174.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;134&#34;
		data-flex-basis=&#34;322px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The status page and twitter showed no activity for the first nine minutes of the outage, but were then updated with erroneous information.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-01-on-running-deployments-via-github/2018-01-10-21-01-19.png&#34;
	width=&#34;2426&#34;
	height=&#34;1788&#34;
	srcset=&#34;https://mike42.me/blog/2018-01-on-running-deployments-via-github/2018-01-10-21-01-19_hu_14e9f08a12e3d456.png 480w, https://mike42.me/blog/2018-01-on-running-deployments-via-github/2018-01-10-21-01-19_hu_49f11b7de856f4f2.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;135&#34;
		data-flex-basis=&#34;325px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2018-01-on-running-deployments-via-github/2018-01-10-21-11-00.png&#34;
	width=&#34;2364&#34;
	height=&#34;1516&#34;
	srcset=&#34;https://mike42.me/blog/2018-01-on-running-deployments-via-github/2018-01-10-21-11-00_hu_262f08337b4267b5.png 480w, https://mike42.me/blog/2018-01-on-running-deployments-via-github/2018-01-10-21-11-00_hu_a614d1d30b6147b7.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;155&#34;
		data-flex-basis=&#34;374px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Meanwhile, the website started displaying unicorns.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2018-01-on-running-deployments-via-github/2018-01-10-21-03-56.png&#34;
	width=&#34;2070&#34;
	height=&#34;1488&#34;
	srcset=&#34;https://mike42.me/blog/2018-01-on-running-deployments-via-github/2018-01-10-21-03-56_hu_dabc04c9d8807d9b.png 480w, https://mike42.me/blog/2018-01-on-running-deployments-via-github/2018-01-10-21-03-56_hu_79838262d154f346.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;139&#34;
		data-flex-basis=&#34;333px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;If you use GitHub regularly, you might know that this is not a rare event. I don&amp;rsquo;t have any data on how often GitHub is actually broken, but based on that status page, I&amp;rsquo;m not sure that they know either.&lt;/p&gt;
&lt;h2 id=&#34;why-i-dont-deploy-via-github&#34;&gt;Why I don&amp;rsquo;t deploy via GitHub
&lt;/h2&gt;&lt;p&gt;Quick story - around May 2013, a website that I maintained started rendering incorrectly because of a bug in my code: I had made some MySQL fields &lt;code&gt;TEXT&lt;/code&gt; type, which have a limited size, and part of the application had exceeded the limit, resulting in truncated pages.&lt;/p&gt;
&lt;p&gt;This app is written in PHP, and my deployment workflow at the time involved pushing up a change to GitHub, then triggering a &lt;code&gt;git pull&lt;/code&gt; on the server, which ran an update script to bring everything up to speed.&lt;/p&gt;
&lt;p&gt;In this case, I was on mobile internet, so I diagnosed the problem and prepared a hotfix on my laptop. When I tried to push it to GitHub, it was offline. I ended up logging in and running a few &lt;code&gt;ALTER TABLE&lt;/code&gt; statements over SSH, which is a long shot from the robust deployment pipeline I had planned to use.&lt;/p&gt;
&lt;p&gt;There are some emerging SaaS products that offer to deploy directly from GitHub. For example, I use Travis CI extensively for open source, and you can hook it up with deployment keys.&lt;/p&gt;
&lt;p&gt;These product seems really promising, but I imagine that an error message containing rainbow unicorns would not be very funny if you needed to fix something in a hurry. This particular app is still deployed with a &lt;code&gt;git pull&lt;/code&gt;, but I&amp;rsquo;ve started to avoid mixing deployment with version control, so that I can run a build and deploy anywhere in case of emergency.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to use a Radeon graphics card on Debian 9</title>
        <link>https://mike42.me/blog/2018-01-how-to-use-a-radeon-graphics-card-on-debian-9</link>
        <pubDate>Thu, 04 Jan 2018 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2018-01-how-to-use-a-radeon-graphics-card-on-debian-9</guid>
        <description>&lt;p&gt;I &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2013-03-01_debian_xfce_on_toshiba_nb550d&#34; &gt;have&lt;/a&gt; &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2013-11-27_debian_7_on_the_hp_dm-1&#34; &gt;previously&lt;/a&gt; &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi&#34; &gt;blogged&lt;/a&gt; &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/how-to-edit-emulator-flags-in-android-studio&#34; &gt;about&lt;/a&gt; Radeon graphics cards on different Debian installs.&lt;/p&gt;
&lt;p&gt;ATI has now released a new free driver which works brilliantly on Debian. In the past, Debian users had to choose between using the community-provided free software driver, or the proprietary one. Generally the proprietary driver was more feature-rich, but the free driver worked more reliably across upgrades. So now, you can safely ignore old guides and start using it.&lt;/p&gt;
&lt;p&gt;This is a quick guide about how to do that.&lt;/p&gt;
&lt;h2 id=&#34;upgrade&#34;&gt;Upgrade
&lt;/h2&gt;&lt;p&gt;Make sure you are on Debian 9 (Stretch) or newer.&lt;/p&gt;
&lt;p&gt;These steps apply to a fresh install.&lt;/p&gt;
&lt;h2 id=&#34;identify&#34;&gt;Identify
&lt;/h2&gt;&lt;p&gt;You should use &lt;code&gt;lspci&lt;/code&gt; to confirm that you have an ATI card.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ lspci | grep Radeon
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;01:00.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Tahiti XT [Radeon HD 7970/8970 OEM / R9 280X]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;install-firmware&#34;&gt;Install firmware
&lt;/h2&gt;&lt;p&gt;You need to install a package called &lt;code&gt;firmware-linux-free&lt;/code&gt; to get the driver working at all. If you want decent graphics performance, you will need &lt;code&gt;firmware-linux-nonfree&lt;/code&gt; as well, which involves adding non-free sources.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nano /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add the words &amp;ldquo;contrib non-free&amp;rdquo; to the end of your mirror:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb http://.../debian/debian/ stretch main contrib non-free
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add the packages:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get update
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install firmware-linux-free firmware-linux-nonfree
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And reboot:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;reboot
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;what-thats-it&#34;&gt;What, that&amp;rsquo;s it?
&lt;/h2&gt;&lt;p&gt;Well, yes, for a fresh install that&amp;rsquo;s it. If your install is old, you might also have to remove old drivers or install the &lt;code&gt;xserver-xorg-video-amdgpu&lt;/code&gt; and &lt;code&gt;xserver-xorg-video-ati packages&lt;/code&gt; (in my case, these were already installed).&lt;/p&gt;
&lt;p&gt;The &lt;a class=&#34;link&#34; href=&#34;https://wiki.debian.org/AtiHowTo&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Debian Wiki AtiHowto&lt;/a&gt; contains some more detailed information, most of which is not relevant for a simple desktop setup.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to assemble a Linux software RAID array on a different computer</title>
        <link>https://mike42.me/blog/2017-12-how-to-assemble-linux-software-raid-on-a-new-computer</link>
        <pubDate>Thu, 28 Dec 2017 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2017-12-how-to-assemble-linux-software-raid-on-a-new-computer</guid>
        <description>&lt;p&gt;With Linux software RAID, if you ever toast your computer, you can retrieve the disks and open up the array on a different computer.&lt;/p&gt;
&lt;p&gt;They appear as &amp;ldquo;Linux Software RAID Member&amp;rdquo; in the disk utility.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2017-12-how-to-assemble-linux-software-raid-on-a-new-computer/2017-12-raid01.png&#34;
	width=&#34;1604&#34;
	height=&#34;1008&#34;
	srcset=&#34;https://mike42.me/blog/2017-12-how-to-assemble-linux-software-raid-on-a-new-computer/2017-12-raid01_hu_bea27cceba328dba.png 480w, https://mike42.me/blog/2017-12-how-to-assemble-linux-software-raid-on-a-new-computer/2017-12-raid01_hu_6e17becc1295103b.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;159&#34;
		data-flex-basis=&#34;381px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Simply install mdadm, and scan for arrays:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo apt-get install mdadm
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo mdadm --assemble --scan
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mdadm: /dev/md/0 has been started with 2 drives.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The array will then appear as a new disk, which can be formatted, mounted, or cloned via the usual tools.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2017-12-how-to-assemble-linux-software-raid-on-a-new-computer/2017-12-raid02.png&#34;
	width=&#34;1600&#34;
	height=&#34;760&#34;
	srcset=&#34;https://mike42.me/blog/2017-12-how-to-assemble-linux-software-raid-on-a-new-computer/2017-12-raid02_hu_9b14ca168faeda80.png 480w, https://mike42.me/blog/2017-12-how-to-assemble-linux-software-raid-on-a-new-computer/2017-12-raid02_hu_5305d735d884fdf8.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;2017-raid02.png&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;210&#34;
		data-flex-basis=&#34;505px&#34;
	
&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Crowd-sourced POS printer compatibility site is online</title>
        <link>https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online</link>
        <pubDate>Sun, 26 Nov 2017 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online</guid>
        <description>&lt;p&gt;Point-of-sale (POS) printers are all different, so the implementation of the more advanced ESC/POS features varies considerably between vendors and models.&lt;/p&gt;
&lt;p&gt;Some months ago I extracted compatibility information out of the &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;escpos-php&lt;/a&gt; library, so that it could be used by the &lt;a class=&#34;link&#34; href=&#34;https://github.com/python-escpos/python-escpos&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;python-escpos&lt;/a&gt; team as well. We&amp;rsquo;re still in the early stages, but both of these projects now have similar compatibility features.&lt;/p&gt;
&lt;p&gt;You can the new shared database on GitHub as &lt;a class=&#34;link&#34; href=&#34;https://github.com/receipt-print-hq/escpos-printer-db&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;receipt-print-hq/escpos-printer-db&lt;/a&gt;, and I&amp;rsquo;m beginning to add it to some printing projects that need it.&lt;/p&gt;
&lt;p&gt;Today I&amp;rsquo;m blogging a few screen captures from the new web viewer for this database that has come out today, hosted &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/escpos-printer-db/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;here&lt;/a&gt; (source code &lt;a href=&#34;https://github.com/receipt-print-hq/escpos-printer-db-browser&#34;&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online/00-main.png&#34;
	width=&#34;1024&#34;
	height=&#34;1341&#34;
	srcset=&#34;https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online/00-main_hu_a54b0ab5f9b6d8a4.png 480w, https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online/00-main_hu_4274a6152ac22167.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;escpos-printer-db landing page&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;76&#34;
		data-flex-basis=&#34;183px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;character-encodings&#34;&gt;Character encodings
&lt;/h2&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online/01-encodings.png&#34;
	width=&#34;1024&#34;
	height=&#34;3003&#34;
	srcset=&#34;https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online/01-encodings_hu_da2067046d3be98.png 480w, https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online/01-encodings_hu_e4ef0f533bea5b91.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;escpos-printer-db character encoding detail&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;34&#34;
		data-flex-basis=&#34;81px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online/02-encoding.png&#34;
	width=&#34;1024&#34;
	height=&#34;1020&#34;
	srcset=&#34;https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online/02-encoding_hu_d67bb4fea6760aa0.png 480w, https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online/02-encoding_hu_8cb2a122fc1f99fc.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;escpos-printer-db character encoding list&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;100&#34;
		data-flex-basis=&#34;240px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;vendors&#34;&gt;Vendors
&lt;/h2&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online/03-vendors.png&#34;
	width=&#34;1024&#34;
	height=&#34;861&#34;
	srcset=&#34;https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online/03-vendors_hu_5df3103fe6d4d071.png 480w, https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online/03-vendors_hu_96d8cb88825bc6fe.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;escpos-printer-db vendor list&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;118&#34;
		data-flex-basis=&#34;285px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online/04-vendor.png&#34;
	width=&#34;1024&#34;
	height=&#34;651&#34;
	srcset=&#34;https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online/04-vendor_hu_1148e1095ba9842a.png 480w, https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online/04-vendor_hu_82012606f6fa4bd0.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;escpos-printer-db vendor detail&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;157&#34;
		data-flex-basis=&#34;377px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;printer-profiles&#34;&gt;Printer profiles
&lt;/h2&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online/05-profiles.png&#34;
	width=&#34;1024&#34;
	height=&#34;1155&#34;
	srcset=&#34;https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online/05-profiles_hu_d1b0036bbba3a50f.png 480w, https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online/05-profiles_hu_9d872b4cf8a8541c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;escpos-printer-db printer profile list&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;88&#34;
		data-flex-basis=&#34;212px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online/06-profile.png&#34;
	width=&#34;1024&#34;
	height=&#34;5522&#34;
	srcset=&#34;https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online/06-profile_hu_b881aa9faaa7e036.png 480w, https://mike42.me/blog/2017-11-crowd-sourced-pos-printer-compatibility-site-is-online/06-profile_hu_8d5d1ccfcd2d303e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;escpos-printer-db printer profile detail&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;18&#34;
		data-flex-basis=&#34;44px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;tech-used&#34;&gt;Tech used
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;ve used &lt;a class=&#34;link&#34; href=&#34;http://materializecss.com/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;materialize.css&lt;/a&gt; with &lt;a class=&#34;link&#34; href=&#34;http://backbonejs.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;backbone.js&lt;/a&gt; and &lt;a class=&#34;link&#34; href=&#34;https://jquery.com/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;jQuery&lt;/a&gt;. This is the first time I&amp;rsquo;ve attempted using materialize - I would normally have used &lt;a class=&#34;link&#34; href=&#34;https://getbootstrap.com/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;bootstrap.css&lt;/a&gt; for this sort of task.&lt;/p&gt;
&lt;p&gt;The back-end data is generated with Python, but the actual site is served as a single-page application, with static JSON files hosting the data.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>escpos-php 1.6 released</title>
        <link>https://mike42.me/blog/2017-11-escpos-php-1-6-released</link>
        <pubDate>Sun, 05 Nov 2017 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2017-11-escpos-php-1-6-released</guid>
        <description>&lt;p&gt;Another update to the open source receipt printing library &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;escpos-php&lt;/a&gt; has been released today. For composer users, it is available as &lt;a class=&#34;link&#34; href=&#34;https://packagist.org/packages/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/escpos-php&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is expected to be the final release in the 1.x series. Newer versions will drop support for some end-of-life PHP versions.&lt;/p&gt;
&lt;p&gt;The &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php/releases/tag/v1.6&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;v1.6 release notes&lt;/a&gt; detail the changes and lists 13 additional printers tested out by the user base.&lt;/p&gt;&lt;/p&gt;
&lt;p&gt;Please direct any bug reports to &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php/issues&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;the issue tracker on GitHub&lt;/a&gt;. The &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/tag/escpos-php&#34; &gt;escpos-php&lt;/a&gt; tag on this blog has some tips and examples.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll also call out some related projects that I&amp;rsquo;ve been involved with, which you should consider contributing to if you are working with thermal receipt printers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/receipt-print-hq/escpos-printer-db&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;receipt-print-hq/escpos-printer-db&lt;/a&gt; - Crowd-sourced database of printer features. Add your printer for better support in open source drivers!&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/receipt-print-hq/escpos-tools&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;receipt-print-hq/escpos-tools&lt;/a&gt; - Tools to work with ESC/POS binary, including text or image extraction, HTML conversion.&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/receipt-print-hq/chrome-raw-print&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;receipt-print-hq/chrome-raw-print&lt;/a&gt; - A browser plugin to access local printers from a web-page.&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>mdcheckr: Practical testing for Markdown files</title>
        <link>https://mike42.me/blog/2017-06-mdcheckr-practical-testing-for-markdown-files</link>
        <pubDate>Sun, 25 Jun 2017 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2017-06-mdcheckr-practical-testing-for-markdown-files</guid>
        <description>&lt;p&gt;If you are a continuous integration enthusiast, you might be annoyed by  preventable errors in project documentation.&lt;/p&gt;
&lt;p&gt;I recently found a broken link in one project&amp;rsquo;s documentation, and a syntax error in an example on another project. I quickly wrote up a simple tool to detect this type of issue, solving the problem for me.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ mdcheckr README.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Checking README.md ..
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- Code block starting line 21 (language: bash) [ OK ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- Link https://travis-ci.org/receipt-print-hq/escpos-tools [ OK ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- Link https://getcomposer.org/ [ OK ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- Link doc/esc2text.md [ OK ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- Link doc/esc2html.md [ OK ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- Link doc/escimages.md [ OK ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- Link CONTRIBUTING.md [ OK ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- Link LICENSE.md [ OK ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- Image https://travis-ci.org/receipt-print-hq/escpos-tools.svg?branch=master [ OK ]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I disregarded some existing &amp;ldquo;linter&amp;rdquo; tools. I don&amp;rsquo;t believe that it is necessarily productive for small projects to enforce a style-based quality gate for Markdown, but you may be able to configure these tools to be less pedantic. My goal here was to simply churn out a script which could reject objectively broken Markdown files.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve posted this project to GitHub as &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/mdcheckr&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mdcheckr&lt;/a&gt;. It is available as a package for Debian, Ubuntu, and RHEL/CentOS. Travis CI users may be interested to check out &lt;a class=&#34;link&#34; href=&#34;https://github.com/receipt-print-hq/escpos-tools/pull/32&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this pull request&lt;/a&gt;, where mdcheckr is added to the project&amp;rsquo;s build.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to access a raw network printer as a file on Linux</title>
        <link>https://mike42.me/blog/2017-06-how-to-access-a-raw-network-printer-as-a-file-on-linux</link>
        <pubDate>Mon, 12 Jun 2017 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2017-06-how-to-access-a-raw-network-printer-as-a-file-on-linux</guid>
        <description>&lt;p&gt;I got this interesting question on my blog post &amp;lsquo;&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2014-10-26-setting-up-an-epson-receipt-printer&#34; &gt;Setting up an Epson receipt printer&lt;/a&gt;&amp;rsquo;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Wondering if you had an idea on how to map a linux device to the netcat command so that I could “convert” the printer to be a local one? -Marco&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;I have previously written about the opposite use case: &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2015-04-how-to-use-a-raspberry-pi-as-a-print-server&#34; &gt;How to use a Raspberry Pi as a print server&lt;/a&gt;, where I used &lt;code&gt;netcat&lt;/code&gt; to pass data to a local USB printer.&lt;/p&gt;
&lt;h2 id=&#34;the-setup&#34;&gt;The setup
&lt;/h2&gt;&lt;p&gt;In this setup, I will assume that you have a working Ethernet printer, which accepts raw data on port 9100.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2017-06-how-to-access-a-raw-network-printer-as-a-file-on-linux/diagram.png&#34;
	width=&#34;301&#34;
	height=&#34;60&#34;
	srcset=&#34;https://mike42.me/blog/2017-06-how-to-access-a-raw-network-printer-as-a-file-on-linux/diagram_hu_c0d537e108bc2fdc.png 480w, https://mike42.me/blog/2017-06-how-to-access-a-raw-network-printer-as-a-file-on-linux/diagram_hu_7d2dc36511a41573.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;501&#34;
		data-flex-basis=&#34;1204px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The aim is to make this appear as a file, so that you can print to it as if it were a local USB printer:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2017-06-how-to-access-a-raw-network-printer-as-a-file-on-linux/diagram2.png&#34;
	width=&#34;423&#34;
	height=&#34;60&#34;
	srcset=&#34;https://mike42.me/blog/2017-06-how-to-access-a-raw-network-printer-as-a-file-on-linux/diagram2_hu_7c90754b3e5ece66.png 480w, https://mike42.me/blog/2017-06-how-to-access-a-raw-network-printer-as-a-file-on-linux/diagram2_hu_5ff69625ff449b07.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;705&#34;
		data-flex-basis=&#34;1692px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;before-you-begin&#34;&gt;Before you begin
&lt;/h2&gt;&lt;p&gt;Make sure you have &lt;code&gt;netcat&lt;/code&gt;. It&amp;rsquo;s not used for the real setup, but you will need it for testing. There are a few versions of this tool around, the one used here is from the Debian repositories:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install netcat
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Verify that your printer accepts text on port 9100 via &lt;code&gt;netcat&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;echo &amp;#34;Hello world&amp;#34; | nc -q 1 192.168.x.y 9100
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Set up a fake printer on localhost, and leave it running:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nc -klp 9100
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, test that your fake printer shows output when you send it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;echo &amp;#34;Hello world&amp;#34; | nc -q 1 127.0.0.1 9100
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;why-im-not-using-___&#34;&gt;Why I&amp;rsquo;m not using ___
&lt;/h2&gt;&lt;h3 id=&#34;devtcp&#34;&gt;/dev/tcp
&lt;/h3&gt;&lt;p&gt;If you search for how to redirect data to a TCP socket, a common suggestion is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;echo &amp;#34;Hello world&amp;#34; &amp;gt; /dev/tcp/127.0.0.1/9100
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This uses a bash built-in, so unless your use case involves printing from bash, read on.&lt;/p&gt;
&lt;h3 id=&#34;cups&#34;&gt;CUPS
&lt;/h3&gt;&lt;p&gt;CUPS does not expose the printer as a file, which is the aim here. It also takes a few seconds to print, so we get much faster results if we remove CUPS from the loop and speak to the printer directly.&lt;/p&gt;
&lt;h2 id=&#34;use-socat-to-move-data&#34;&gt;Use socat to move data
&lt;/h2&gt;&lt;p&gt;Socat is capable of making a FIFO file (&amp;lsquo;pipe&amp;rsquo;), and writing this out over the network.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install socat
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Redirect &lt;code&gt;/tmp/my-printer&lt;/code&gt; to &lt;code&gt;localhost:9100&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;socat PIPE:/tmp/my-printer TCP:localhost:9100
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, test that you can see the printer file and write to it. The text sent here should appear on your local netcat &amp;ldquo;fake printer&amp;rdquo;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;echo &amp;#34;Hello world&amp;#34; &amp;gt; /tmp/my-printer
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This file is a &amp;ldquo;pipe&amp;rdquo;, so it behaves very similarly to a character device.&lt;/p&gt;
&lt;p&gt;If the connection is dropped, socat will exit, and the file will be deleted.&lt;/p&gt;
&lt;p&gt;There are some big problems though:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If your printer is offline, and you try to print, then data will be left in regular file at &amp;ldquo;/tmp/my-printer&amp;rdquo;, which breaks this setup&lt;/li&gt;
&lt;li&gt;This is not a self-restarting service, nor does it start on boot&lt;/li&gt;
&lt;li&gt;Only the user who runs the command can print&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;setting-this-up-as-a-service&#34;&gt;Setting this up as a service
&lt;/h2&gt;&lt;p&gt;The &lt;code&gt;usblp&lt;/code&gt; driver allows anybody from the &lt;code&gt;lp&lt;/code&gt; group to print, so we will try to do something similar, and get a group-writable pipe:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ls /dev/usb/lp0  -Ahl
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;crw-rw---- 1 root lp 180, 0 Jun 12 12:51 /dev/usb/lp0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We don&amp;rsquo;t need to run &lt;code&gt;socat&lt;/code&gt; as root, so make a new user called &lt;code&gt;fileprint&lt;/code&gt; who is in the &lt;code&gt;lp&lt;/code&gt; group.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;useradd --groups lp fileprint
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add yourself to the &lt;code&gt;lp&lt;/code&gt; group as well:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;usermod -a -G lp mike
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, write this &lt;code&gt;systemd&lt;/code&gt; service file to &lt;code&gt;/etc/systemd/system/fileprint.service&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[Unit]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Description=fileprint
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;After=network.target
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[Service]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;User=fileprint
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Group=lp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ExecStartPre=/usr/bin/mkfifo -m &amp;#39;0664&amp;#39; /var/run/fileprint/printer
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ExecStart=/usr/bin/socat PIPE:/var/run/fileprint/printer TCP:127.0.0.1:9100
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Restart=always
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;RuntimeDirectory=fileprint
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What&amp;rsquo;s going on here? This service file:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Runs &lt;code&gt;socat&lt;/code&gt; as user &lt;code&gt;fileprint&lt;/code&gt; and group &lt;code&gt;lp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Manages a runtime directory at &lt;code&gt;/var/run/fileprint&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Creates a pipe that is group-writeable at &lt;code&gt;/var/run/fileprint/printer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Forwards traffic to &lt;code&gt;127.0.0.1:9100&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Re-starts automatically&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Load and start the service:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;systemctl&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;daemon&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;reload&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;systemctl&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fileprint&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;systemctl&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fileprint&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Test out printing to your local netcat &amp;ldquo;fake printer&amp;rdquo;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Test&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fileprint&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;printer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that if you are not in the &lt;code&gt;lp&lt;/code&gt; group (check with &lt;code&gt;groups&lt;/code&gt; command), you should expect a permission error here - just the same as &lt;code&gt;usblp&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Next, replace &lt;code&gt;127.0.0.1&lt;/code&gt; with your real printer IP, reload systemd, and restart the service:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;nano&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;etc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;systemd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;system&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fileprint&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;systemctl&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;daemon&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;reload&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;systemctl&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;restart&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fileprint&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;systemctl&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fileprint&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Test it again, and your actual printer should print a line of text this time:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Test&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fileprint&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;printer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, enable on boot:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;systemctl enable fileprint
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When the printer is unplugged, the &lt;code&gt;/var/run/fileprint&lt;/code&gt; directory will vanish, so that you can see the missing printer as a &amp;ldquo;File Not Found&amp;rdquo; error — just the same as &lt;code&gt;usblp&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;drawbacks&#34;&gt;Drawbacks
&lt;/h2&gt;&lt;p&gt;This will hold a connection open at all times, which (depending on your printer) may prevent other computers from using it.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>The 5890 printer does not support barcodes</title>
        <link>https://mike42.me/blog/2017-06-the-5890-printer-does-not-support-barcodes</link>
        <pubDate>Mon, 12 Jun 2017 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2017-06-the-5890-printer-does-not-support-barcodes</guid>
        <description>&lt;p&gt;I haven&amp;rsquo;t been able to print barcodes on the 5890 model thermal receipt printer, and it looks like other developers can&amp;rsquo;t either.&lt;/p&gt;
&lt;p&gt;The same printer is sold under a few names. As far as I can tell (mainly from bug reports to &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/escpos-php&lt;/a&gt;), these are all the same printer, and could have this issue:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AGPtEK SC35-5890F&lt;/li&gt;
&lt;li&gt;EC Line 5890&lt;/li&gt;
&lt;li&gt;Gainscha GP-5890&lt;/li&gt;
&lt;li&gt;HSPOS HS-589C&lt;/li&gt;
&lt;li&gt;POS-5890&lt;/li&gt;
&lt;li&gt;WinBond 5890&lt;/li&gt;
&lt;li&gt;Zjiang ZJ-5890 or POS-5890&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In my case, I have a Zjiang POS-5890C, which list the barcode command &lt;code&gt;GS k&lt;/code&gt; in its documentation, but does not actually respond to the command.&lt;/p&gt;
&lt;p&gt;Separately, a developer has contacted their vendor and confirmed that this is an error in the documentation.&lt;/p&gt;
&lt;p&gt;A few bookmarks for reference:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/python-escpos/python-escpos/issues/58&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://github.com/python-escpos/python-escpos/issues/58&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://stackoverflow.com/questions/42124722/esc-pos-not-printing-barcodes&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://stackoverflow.com/questions/42124722/esc-pos-not-printing-barcodes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;how-to-test-for-barcode-support-in-usb-printers&#34;&gt;How to test for barcode support in USB printers
&lt;/h2&gt;&lt;p&gt;Get yourself a Linux computer or VM, set up the printer with &lt;code&gt;usblp&lt;/code&gt;, and run this command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;echo -e &amp;#39;\x1d\x6b\x04000\x00&amp;#39; &amp;gt; /dev/usb/lp0\
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This command prints a &lt;code&gt;CODE39&lt;/code&gt; barcode containing &amp;lsquo;000&amp;rsquo; on printers which support barcodes, and prints garbage on printers which do not.&lt;/p&gt;
&lt;p&gt;See also:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2015-03-getting-a-usb-receipt-printer-working-on-linux&#34; &gt;Getting a USB receipt printer working on Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/zxing/zxing&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;ZXing (&amp;ldquo;Zebra Crossing&amp;rdquo;)&lt;/a&gt; - Open source Android app for scanning barcodes&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://stackoverflow.com/questions/30662024/how-to-send-esc-pos-commands-to-thermal-printer-in-linux/44212593#44212593&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;How to send ESC/POS commands to thermal printer in Linux&lt;/a&gt; - Related StackOverflow answer of mine&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>How to add a proper Android Studio launcher on Linux</title>
        <link>https://mike42.me/blog/2017-04-how-to-add-a-proper-android-studio-launcher-on-linux</link>
        <pubDate>Mon, 24 Apr 2017 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2017-04-how-to-add-a-proper-android-studio-launcher-on-linux</guid>
        <description>&lt;p&gt;If you install Android Studio by extracting a Zip file on Linux, it will come without any launch icon. This post assumes that have extracted the install archive to &lt;code&gt;/usr/local&lt;/code&gt; and run any recent version of Linux which has Gnome:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;unzip android-studio-ide-145.3537/39-linux.zip -d /usr/local
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Simply write the following text to &lt;code&gt;~/.local/share/applications/android-studio.desktop&lt;/code&gt; (change paths if your install location differs).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[Desktop Entry]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Comment=Android Studio
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Terminal=false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Name=Android Studio
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Exec=/usr/local/android-studio/bin/studio.sh
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Type=Application
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Icon=/usr/local/android-studio/bin/studio.png
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once you save the file, it will appear in your local applications like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2017-04-how-to-add-a-proper-android-studio-launcher-on-linux/2016-04-android-studio-icon.png&#34;
	width=&#34;499&#34;
	height=&#34;281&#34;
	srcset=&#34;https://mike42.me/blog/2017-04-how-to-add-a-proper-android-studio-launcher-on-linux/2016-04-android-studio-icon_hu_1c05762a47bda27d.png 480w, https://mike42.me/blog/2017-04-how-to-add-a-proper-android-studio-launcher-on-linux/2016-04-android-studio-icon_hu_98345bcd78585701.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This can also be added graphically though the &lt;i&gt;Alacarte&lt;/i&gt; menu editor if you have it installed.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>libgdx 3D particle effects in HTML</title>
        <link>https://mike42.me/blog/2017-04-libgdx-3d-particle-effects-in-html</link>
        <pubDate>Mon, 24 Apr 2017 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2017-04-libgdx-3d-particle-effects-in-html</guid>
        <description>&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2017-04-libgdx-3d-particle-effects-in-html/2017-03-flame.png&#34;
	width=&#34;502&#34;
	height=&#34;632&#34;
	srcset=&#34;https://mike42.me/blog/2017-04-libgdx-3d-particle-effects-in-html/2017-03-flame_hu_51106cbe8ec02fae.png 480w, https://mike42.me/blog/2017-04-libgdx-3d-particle-effects-in-html/2017-03-flame_hu_20a02133a0ebf429.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;79&#34;
		data-flex-basis=&#34;190px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;It is &lt;a href=&#34;https://github.com/libgdx/libgdx/issues/3871&#34;&gt;not immediately obvious&lt;/a&gt; in libgdx why the 3D particle effects don&amp;rsquo;t work in a HTML target. I&amp;rsquo;m sharing this snippet for future readers.&lt;/p&gt;
&lt;p&gt;In short, the &amp;ldquo;reflection cache&amp;rdquo; that is created from the Java code does not include everything required, since many of the classes are only referenced at runtime, when the particle definition is loaded.&lt;/p&gt;
&lt;p&gt;These class names are visible in the saved files from the 3D effects editor:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cat engine.p | fold -w 80
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{unique:{billboardBatch:{class:com.badlogic.gdx.graphics.g3d.particles.ResourceD
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ata$SaveData,data:{cfg:{class:com.badlogic.gdx.graphics.g3d.particles.batches.Bi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;llboardParticleBatch$Config,mode:Screen}},indices:[0]}},data:[],assets:[{filenam
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;e:&amp;#34;pre_particle.png&amp;#34;,type:com.badlogic.gdx.graphics.Texture}],resource:{class:co
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;....
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At runtime, this message is displayed on the web page:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;GwtApplication: exception: com.badlogic.gdx.utils.GdxRuntimeException: Could not submit AsyncTask: Error reading file: (filename)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;com.badlogic.gdx.utils.GdxRuntimeException: Could not submit AsyncTask: Error reading file: (filename)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Could not submit AsyncTask: Error reading file: (filename)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Error reading file: (filename)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Couldn&amp;#39;t find Type for class &amp;#39;com.badlogic.gdx.graphics.g3d.particles.batches.BillboardParticleBatch$Config&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The reflection is documented on the libgdx Wiki &lt;a href=&#34;https://github.com/libgdx/libgdx/wiki/Reflection&#34;&gt;here&lt;/a&gt;, and notes that-&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;*.gwt.xml files store this data&lt;/li&gt;
&lt;li&gt;dependencies defined in the Java are loaded automatically&lt;/li&gt;
&lt;li&gt;inner classes are also loaded automatically, no need to add them separately&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With this in mind, I added the following two lines to the root element in a file called &lt;code&gt;GdxDefinition.gwt.xml&lt;/code&gt;-&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;lt;extend-configuration-property name=&amp;#34;gdx.reflect.include&amp;#34; value=&amp;#34;com.badlogic.gdx.graphics.g3d.particles.batches.BillboardParticleBatch&amp;#34; /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;lt;extend-configuration-property name=&amp;#34;gdx.reflect.include&amp;#34; value=&amp;#34;com.badlogic.gdx.graphics.g3d.particles.ParticleShader&amp;#34; /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This did the trick, and the 3D particle feature does indeed work in the libgdx HTML target.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>escpos-php 1.5 released</title>
        <link>https://mike42.me/blog/2017-02-escpos-php-1-5-released</link>
        <pubDate>Fri, 10 Feb 2017 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2017-02-escpos-php-1-5-released</guid>
        <description>&lt;p&gt;I&amp;rsquo;ve released another update to the open source receipt printing library &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/escpos-php&lt;/a&gt; today.&lt;/p&gt;
&lt;p&gt;Device support has been continuing to improve. See the &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php/releases/tag/v1.5&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;v1.5 release notes&lt;/a&gt; for all the details.&lt;/p&gt;
&lt;p&gt;Please direct any bug reports to &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php/issues&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;the issue tracker on GitHub&lt;/a&gt;. The &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/tag/escpos-php&#34; &gt;escpos-php tag&lt;/a&gt; on this blog has some posts about the driver for PHP programmers who are looking to use it.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>escpos-php 1.4 released</title>
        <link>https://mike42.me/blog/2016-10-escpos-php-1-4-released</link>
        <pubDate>Mon, 24 Oct 2016 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2016-10-escpos-php-1-4-released</guid>
        <description>&lt;p&gt;The next minor release of the open source receipt printing library for &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;escpos-php&lt;/a&gt; was published today.&lt;/p&gt;
&lt;p&gt;See the &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php/releases/tag/v1.4&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;release notes&lt;/a&gt; for all the details.&lt;/p&gt;
&lt;p&gt;Aside from the official documentation, if you are a PHP programmer with a receipt printer, you can learn how to use escpos-php by reading the &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/tag/escpos-php&#34; &gt;escpos-php&lt;/a&gt; tag on this blog.&lt;/p&gt;
&lt;p&gt;Please direct any questions or suggestions to &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php/issues&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;the issue tracker on GitHub&lt;/a&gt;.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>OpenWrt setup on Netgear WNR2200</title>
        <link>https://mike42.me/blog/2016-10-openwrt-on-netgear-wnr2200</link>
        <pubDate>Sun, 23 Oct 2016 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2016-10-openwrt-on-netgear-wnr2200</guid>
        <description>&lt;p&gt;I recently wanted to connect some devices for a temporary setup, where a wireless LTE modem would provide Internet access. Unfortunately, one of the devices was not close enough to pick up the signal with its USB WiFi dongle.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-10-openwrt-on-netgear-wnr2200/net1.png&#34;
	width=&#34;449&#34;
	height=&#34;296&#34;
	srcset=&#34;https://mike42.me/blog/2016-10-openwrt-on-netgear-wnr2200/net1_hu_29d0fdb736322ab5.png 480w, https://mike42.me/blog/2016-10-openwrt-on-netgear-wnr2200/net1_hu_ddd67da8a1f8191c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;151&#34;
		data-flex-basis=&#34;364px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Because the modem does not have a LAN port, the usual &amp;ldquo;run a cable&amp;rdquo; solution was out. There&amp;rsquo;s a few other options, from range extenders, to getting better modem, or just upgrading to a &amp;ldquo;real&amp;rdquo; USB WiFi dongle. Before purchasing new hardware, I decided to try re-purposing an old Netgear WNR2200 as a wireless client and 4 port switch.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-10-openwrt-on-netgear-wnr2200/net.svg_-1.png&#34;
	width=&#34;449&#34;
	height=&#34;206&#34;
	srcset=&#34;https://mike42.me/blog/2016-10-openwrt-on-netgear-wnr2200/net.svg_-1_hu_2b9ca171c348e078.png 480w, https://mike42.me/blog/2016-10-openwrt-on-netgear-wnr2200/net.svg_-1_hu_b65dbf357293719f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;217&#34;
		data-flex-basis=&#34;523px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;In this setup, the LTE modem does the heavy lifting, with all of the wireless clients using it for LAN and Internet access. In the next room, the Netgear router is placed close enough to pick up the signal, and an Ethernet cable runs to the PC, beyond the reach of WiFi.&lt;/p&gt;
&lt;h2 id=&#34;deciding-to-re-flash&#34;&gt;Deciding to re-flash
&lt;/h2&gt;&lt;p&gt;Replacing firmware is worth investigating when the hardware is capable, but you aren&amp;rsquo;t given the option to configure it the way you want.&lt;/p&gt;
&lt;p&gt;The Netgear WNR2200 is a low-end wireless router, and the vendor firmware does not support joining a Wi-Fi network as a client.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-10-openwrt-on-netgear-wnr2200/2016-10-router.png&#34;
	width=&#34;1522&#34;
	height=&#34;821&#34;
	srcset=&#34;https://mike42.me/blog/2016-10-openwrt-on-netgear-wnr2200/2016-10-router_hu_50204f8b958e4cc4.png 480w, https://mike42.me/blog/2016-10-openwrt-on-netgear-wnr2200/2016-10-router_hu_ec95174a532a9653.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;185&#34;
		data-flex-basis=&#34;444px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;It also pays to update your research. OpenWrt added support for this router a few days after I bought it, but I hadn&#39;t looked it up again.&lt;/p&gt; 
&lt;h2 id=&#34;uploading-firmware&#34;&gt;Uploading firmware
&lt;/h2&gt;&lt;p&gt;My main resource was &lt;a href=&#34;https://wiki.openwrt.org/toh/netgear/wnr2200&#34;&gt;this page&lt;/a&gt; on the OpenWRT Wiki. Firmware is organised by wireless chipset, then by router model.&lt;/p&gt;
&lt;p&gt;The file I used to update my router was named &lt;code&gt;openwrt-15.05.1-ar71xx-generic-wnr2200-squashfs-factory.img&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is simply uploaded on the &lt;b&gt;Adminisration → Firmware Upgrade&lt;/b&gt; screen:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-10-openwrt-on-netgear-wnr2200/2016-10-router2.png&#34;
	width=&#34;1518&#34;
	height=&#34;821&#34;
	srcset=&#34;https://mike42.me/blog/2016-10-openwrt-on-netgear-wnr2200/2016-10-router2_hu_779de02e323c1492.png 480w, https://mike42.me/blog/2016-10-openwrt-on-netgear-wnr2200/2016-10-router2_hu_33aaec9192c67026.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;184&#34;
		data-flex-basis=&#34;443px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-10-openwrt-on-netgear-wnr2200/2016-10-router3.png&#34;
	width=&#34;1502&#34;
	height=&#34;821&#34;
	srcset=&#34;https://mike42.me/blog/2016-10-openwrt-on-netgear-wnr2200/2016-10-router3_hu_f6c4663524d1be80.png 480w, https://mike42.me/blog/2016-10-openwrt-on-netgear-wnr2200/2016-10-router3_hu_b0633d5c1c114f28.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;182&#34;
		data-flex-basis=&#34;439px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;first-impressions&#34;&gt;First impressions
&lt;/h2&gt;&lt;p&gt;The first thing I noticed was that I lost Wi-Fi, and that the page I had bookmarked for logging in was no longer valid!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-10-openwrt-on-netgear-wnr2200/2016-10-router4.png&#34;
	width=&#34;564&#34;
	height=&#34;298&#34;
	srcset=&#34;https://mike42.me/blog/2016-10-openwrt-on-netgear-wnr2200/2016-10-router4_hu_3680eafb75407fea.png 480w, https://mike42.me/blog/2016-10-openwrt-on-netgear-wnr2200/2016-10-router4_hu_7ed0bdf30c38547f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;189&#34;
		data-flex-basis=&#34;454px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This makes sense, of course. The configuration will not be carried across from the vendor firmware, and a different web administration tool is being used.&lt;/p&gt;
&lt;p&gt;The Linux userspace is very rich compared with vendor firmware. It has things like &lt;code&gt;dmesg&lt;/code&gt;, SSH, &lt;code&gt;ifconfig&lt;/code&gt;, &lt;code&gt;ping&lt;/code&gt;, and even a networked package manager.&lt;/p&gt;
&lt;h2 id=&#34;configuration-checklist&#34;&gt;Configuration checklist
&lt;/h2&gt;&lt;p&gt;I performed all configuration through the web in this setup. The &amp;ldquo;LuCi&amp;rdquo; interface allows setting the Wi-Fi chip into &amp;ldquo;Client&amp;rdquo; mode, and then searching and joining a network. Once this was done, I assigned it as the &amp;ldquo;WAN&amp;rdquo; interface, so that it occupied a single IP address on the Wi-Fi network, and providing a NAT and wired, four port switch.&lt;/p&gt;
&lt;p&gt;There are more advanced, bridged setups that are possible. You should investigate this if you want one network, so that things like printer auto-discovery and internal SSH work consistently. I was only interested in sharing the Internet connection, which is why the setup was so simple.&lt;/p&gt;
&lt;h2 id=&#34;what-didnt-work&#34;&gt;What didn&amp;rsquo;t work
&lt;/h2&gt;&lt;p&gt;USB, but I didn&amp;rsquo;t spend long on this either. I was considering using USB to connect the modem to the Netgear router. The Wiki suggests that this is now possible, but after installing some packages for &amp;ldquo;USB tethering&amp;rdquo; and rebooting, I had no luck. Typing &lt;code&gt;lsusb&lt;/code&gt;, only the &amp;ldquo;root hub&amp;rdquo; was listed, and the device was not getting any power.&lt;/p&gt;
&lt;p&gt;This was necessary for the setup, so I just abandoned it. The vendor firmware couldn&amp;rsquo;t use the USB port for networking either, so no real loss.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>libvirt: Migrate a VM from qemu:///session to qemu:///system</title>
        <link>https://mike42.me/blog/2016-09-libvirt-migrate-a-vm-from-qemusession-to-qemusystem</link>
        <pubDate>Thu, 29 Sep 2016 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2016-09-libvirt-migrate-a-vm-from-qemusession-to-qemusystem</guid>
        <description>&lt;p&gt;In recent versions of the &lt;code&gt;libvirt&lt;/code&gt; virtualisation libraries, you to create and manage virtual machines as a regular user, using the &lt;code&gt;qemu:///session&lt;/code&gt; connection.&lt;/p&gt;
&lt;p&gt;This is great, but the networking is quite limited. I found that machines defined in &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/GNOME_Boxes&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Gnome Boxes&lt;/a&gt; could not speak to each-other, and that libvirt commands for networking were unavailable.&lt;/p&gt;
&lt;p&gt;For this reason, I&amp;rsquo;ve written this quick guide for booting up an existing same VM image under the &lt;code&gt;qemu:///system&lt;/code&gt; instance, which is faster than re-installing the machine. Unlike most sorts of migrations, this leaves the disk image at the same location on the same host machine.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s many different ways to do VM&amp;rsquo;s in Linux. This setup will be useful only if you use libvirt/kvm using qcow2 images on Debian. As always, consider doing a backup before trying new things.&lt;/p&gt;
&lt;h2 id=&#34;configuration-files&#34;&gt;Configuration files
&lt;/h2&gt;&lt;p&gt;First, find your virtual machine in &lt;code&gt;virsh&lt;/code&gt;, and dump its configuration to a text file in your home directory, as a regular user.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ virsh list --all
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; Id    Name                           State
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;----------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; -     foo-machine                    shut off
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ virsh dumpxml foo-machine &amp;gt; foo-machine.xml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now remove the VM definition from your user:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ virsh undefine foo-machine
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Domain foo-machine has been undefined
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Import the definitions into virsh as the root user:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo virsh define foo-machine.xml 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Domain foo-machin defined from foo-machine.xml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Attempt to start the new VM definition. Depending on where the disk image is, expect an error.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo virsh start foo-machine
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;disk-images&#34;&gt;Disk images
&lt;/h2&gt;&lt;p&gt;The disk image needs to be accessible to the &lt;code&gt;libvirt-qemu&lt;/code&gt; user. There&amp;rsquo;s two basic ways to achieve this: Re-permission the directories above it, or move it.&lt;/p&gt;
&lt;p&gt;I chose to just re-permission it, since it&amp;rsquo;s not an issue to have world-readable directories on this particular box:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cat foo-machine.xml | grep source
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &amp;lt;source file=&amp;#39;/home/example/.local/share/gnome-boxes/images/foo-machine&amp;#39;/&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This one-liner outputs the commands to run to make a directory work/navigable:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-mysql&#34; data-lang=&#34;mysql&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dir&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=`&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pwd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;while&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;$dir&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;do&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;echo&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;chmod o+x,g+x \&amp;#34;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dir&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dir&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=`&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dirname&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;err&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dir&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;done&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;chmod&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;o&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;g&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/home/example/.local/share/gnome-boxes/images&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;chmod&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;o&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;g&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/home/example/.local/share/gnome-boxes&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;chmod&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;o&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;g&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/home/example/.local/share&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;chmod&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;o&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;g&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/home/example/.local&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;chmod&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;o&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;g&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/home/example&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;chmod&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;o&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;g&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/home&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the user account needs to be able to write as well:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo chown libvirt-qemu /home/example/.local/share/gnome-boxes/images/foo-machine
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once you have the permissions right, the VM should start, using the same command as before:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo virsh start foo-machine
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;More importantly, you can now hook up &lt;a class=&#34;link&#34; href=&#34;https://virt-manager.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;virt-manager&lt;/a&gt; and view your machine on &lt;code&gt;qemu:///system&lt;/code&gt;, allowing you to configure the VM with any network settings you need.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to print PDF417 codes with escpos-php</title>
        <link>https://mike42.me/blog/2016-09-how-to-print-pdf417-codes-with-escpos-php</link>
        <pubDate>Thu, 08 Sep 2016 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2016-09-how-to-print-pdf417-codes-with-escpos-php</guid>
        <description>&lt;p&gt;This post is a reference for printing PDF417 2-dimensional codes to a receipt printer, using the &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;escpos-php&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve got an older post about &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2015-04-howto-qrcodes-on-receipts-with-escpos-php&#34; &gt;printing QR codes with escpos-php&lt;/a&gt;, which follows the same format and has some more background and links if you haven&amp;rsquo;t printed receipts from PHP before.&lt;/p&gt;
&lt;p&gt;Straight from the documentation, the syntax for the command that I&amp;rsquo;m demonstrating is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;pdf417Code($content, $width, $heightMultiplier, $dataColumnCount, $ec, $options)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Print a two-dimensional data code using the PDF417 standard.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;string $content&lt;/code&gt;: Text or numbers to store in the code&lt;/li&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;number $width&lt;/code&gt;: Width of a module (pixel) in the printed code. Default is 3 dots.&lt;/li&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;number $heightMultiplier&lt;/code&gt;: Multiplier for height of a module. Default is 3 times the width.&lt;/li&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;number $dataColumnCount&lt;/code&gt;: Number of data columns to use. 0 (default) is to auto-calculate. Smaller numbers will result in a narrower code, making larger pixel sizes possible. Larger numbers require smaller pixel sizes.&lt;/li&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;real $ec&lt;/code&gt;: Error correction ratio, from 0.01 to 4.00. Default is 0.10 (10%).&lt;/li&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;number $options&lt;/code&gt;: Standard code Printer::PDF417_STANDARD with start/end bars, or truncated code Printer::PDF417_TRUNCATED with start bars only.&lt;/li&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;
&lt;p&gt;These PDF417 snippets above appear in the &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php/example&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;examples&lt;/a&gt; of escpos-php.&lt;/p&gt;
&lt;h2 id=&#34;simple-example&#34;&gt;Simple example
&lt;/h2&gt;&lt;p&gt;A basic code that just says &amp;rsquo;testing 123&amp;rsquo;, and a demonstration of a narrower code that has been aligned:&lt;/p&gt;



&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-09-escpos-pdf417-01-demo&#34;
      id=&#34;tabs-post-2016-09-escpos-pdf417-01-demo-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2016-09-escpos-pdf417-01-demo-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2016-09-how-to-print-pdf417-codes-with-escpos-php/2016-09-escpos-pdf417-01-demo.png&#34;
	width=&#34;350&#34;
	height=&#34;157&#34;
	srcset=&#34;https://mike42.me/blog/2016-09-how-to-print-pdf417-codes-with-escpos-php/2016-09-escpos-pdf417-01-demo_hu_c747b0d094b3ebc4.png 480w, https://mike42.me/blog/2016-09-how-to-print-pdf417-codes-with-escpos-php/2016-09-escpos-pdf417-01-demo_hu_fb58fdf6f46b4bdc.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;222&#34;
		data-flex-basis=&#34;535px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-09-escpos-pdf417-01-demo&#34;
      id=&#34;tabs-post-2016-09-escpos-pdf417-01-demo-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2016-09-escpos-pdf417-01-demo-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Most simple example
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;PDF417 code demo&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$testStr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Testing 123&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;pdf417Code&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testStr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Most simple example&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Demo that alignment is the same as text
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setJustification&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;JUSTIFY_CENTER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;pdf417Code&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testStr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Same content, narrow and centred&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setJustification&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2 id=&#34;error-correction&#34;&gt;Error correction
&lt;/h2&gt;&lt;p&gt;This implementation accepts an error correction ratio as a percentage. The minimum is 1%, the highest is 400%, expressed as a decimal (0.01 - 4.00).&lt;/p&gt;
&lt;p&gt;Higher error correction settings create lager codes that are more resilient to scanning errors due to damage.&lt;/p&gt;



&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-09-escpos-pdf417-02-ec&#34;
      id=&#34;tabs-post-2016-09-escpos-pdf417-02-ec-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2016-09-escpos-pdf417-02-ec-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2016-09-how-to-print-pdf417-codes-with-escpos-php/2016-09-escpos-pdf417-02-ec.png&#34;
	width=&#34;350&#34;
	height=&#34;394&#34;
	srcset=&#34;https://mike42.me/blog/2016-09-how-to-print-pdf417-codes-with-escpos-php/2016-09-escpos-pdf417-02-ec_hu_3c1c8089509fde8a.png 480w, https://mike42.me/blog/2016-09-how-to-print-pdf417-codes-with-escpos-php/2016-09-escpos-pdf417-02-ec_hu_f8bb55c68a6a8603.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;88&#34;
		data-flex-basis=&#34;213px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-09-escpos-pdf417-02-ec&#34;
      id=&#34;tabs-post-2016-09-escpos-pdf417-02-ec-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2016-09-escpos-pdf417-02-ec-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Demo of error correction
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Error correction&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$testStr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Testing 123&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$ec&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;0.1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;0.5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;2.0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;4.0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$ec&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$level&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;pdf417Code&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testStr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$level&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Error correction ratio &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$level\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2 id=&#34;pixel-size-width&#34;&gt;Pixel size (width)
&lt;/h2&gt;&lt;p&gt;The same example string, with some different module widths. Note that the blocks in the code scale in bot directions when the width is changed.&lt;/p&gt;
&lt;p&gt;Larger print is easier for a scanner to read, but takes up more paper.&lt;/p&gt;



&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-09-escpos-pdf417-02-pixel&#34;
      id=&#34;tabs-post-2016-09-escpos-pdf417-02-pixel-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2016-09-escpos-pdf417-02-pixel-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2016-09-how-to-print-pdf417-codes-with-escpos-php/2016-09-escpos-pdf417-02-pixel.png&#34;
	width=&#34;350&#34;
	height=&#34;233&#34;
	srcset=&#34;https://mike42.me/blog/2016-09-how-to-print-pdf417-codes-with-escpos-php/2016-09-escpos-pdf417-02-pixel_hu_d76337630d3e490a.png 480w, https://mike42.me/blog/2016-09-how-to-print-pdf417-codes-with-escpos-php/2016-09-escpos-pdf417-02-pixel_hu_4ff383c77aae6c2a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;150&#34;
		data-flex-basis=&#34;360px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-09-escpos-pdf417-02-pixel&#34;
      id=&#34;tabs-post-2016-09-escpos-pdf417-02-pixel-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2016-09-escpos-pdf417-02-pixel-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Change size
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Pixel size&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$testStr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Testing 123&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$sizes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;(minimum)&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;(default)&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;(maximum)&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$sizes&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$label&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;pdf417Code&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testStr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Module width &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$size&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; dots &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$label\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2 id=&#34;height-multiplier&#34;&gt;Height multiplier
&lt;/h2&gt;&lt;p&gt;The height of the modules in the code can also be changed, stretching it do a different degree. PDF417 that are too vertically squashy are more prone to scanning errors.&lt;/p&gt;



&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-09-escpos-pdf417-03-height&#34;
      id=&#34;tabs-post-2016-09-escpos-pdf417-03-height-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2016-09-escpos-pdf417-03-height-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2016-09-how-to-print-pdf417-codes-with-escpos-php/2016-09-escpos-pdf417-03-height.png&#34;
	width=&#34;350&#34;
	height=&#34;285&#34;
	srcset=&#34;https://mike42.me/blog/2016-09-how-to-print-pdf417-codes-with-escpos-php/2016-09-escpos-pdf417-03-height_hu_4a2c5628754f0df2.png 480w, https://mike42.me/blog/2016-09-how-to-print-pdf417-codes-with-escpos-php/2016-09-escpos-pdf417-03-height_hu_db4a3ac025eda944.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;122&#34;
		data-flex-basis=&#34;294px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-09-escpos-pdf417-03-height&#34;
      id=&#34;tabs-post-2016-09-escpos-pdf417-03-height-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2016-09-escpos-pdf417-03-height-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Change height
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Height multiplier&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$testStr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Testing 123&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$sizes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;(minimum)&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;(default)&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;(maximum)&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$sizes&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$label&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;pdf417Code&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testStr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Height multiplier &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$size&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$label\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2 id=&#34;data-column-count&#34;&gt;Data column count
&lt;/h2&gt;&lt;p&gt;The of data columns to print in the code can be customised to produce a narrower code. But beware, if you request a code that&amp;rsquo;s too big for the paper, nothing will be printed!&lt;/p&gt;



&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-09-escpos-pdf417-04-datacol&#34;
      id=&#34;tabs-post-2016-09-escpos-pdf417-04-datacol-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2016-09-escpos-pdf417-04-datacol-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2016-09-how-to-print-pdf417-codes-with-escpos-php/2016-09-escpos-pdf417-04-datacol.png&#34;
	width=&#34;350&#34;
	height=&#34;547&#34;
	srcset=&#34;https://mike42.me/blog/2016-09-how-to-print-pdf417-codes-with-escpos-php/2016-09-escpos-pdf417-04-datacol_hu_79c0e891a8e4b44e.png 480w, https://mike42.me/blog/2016-09-how-to-print-pdf417-codes-with-escpos-php/2016-09-escpos-pdf417-04-datacol_hu_8044ea49762403eb.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;63&#34;
		data-flex-basis=&#34;153px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-09-escpos-pdf417-04-datacol&#34;
      id=&#34;tabs-post-2016-09-escpos-pdf417-04-datacol-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2016-09-escpos-pdf417-04-datacol-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Change data column count
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Data column count&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$testStr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Testing 123&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$columnCounts&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;(auto, default)&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;mi&#34;&gt;30&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;(maximum, doesnt fit!)&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$columnCounts&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$columnCount&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$label&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;pdf417Code&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testStr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$columnCount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Column count &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$columnCount&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$label\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2 id=&#34;truncated-code-option&#34;&gt;Truncated code option
&lt;/h2&gt;&lt;p&gt;Use this setting to select the alternative, &amp;rsquo;truncated&amp;rsquo; code format.&lt;/p&gt;



&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-09-escpos-pdf417-05-options&#34;
      id=&#34;tabs-post-2016-09-escpos-pdf417-05-options-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2016-09-escpos-pdf417-05-options-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2016-09-how-to-print-pdf417-codes-with-escpos-php/2016-09-escpos-pdf417-05-options.png&#34;
	width=&#34;350&#34;
	height=&#34;168&#34;
	srcset=&#34;https://mike42.me/blog/2016-09-how-to-print-pdf417-codes-with-escpos-php/2016-09-escpos-pdf417-05-options_hu_ebc3436aa4bce8c3.png 480w, https://mike42.me/blog/2016-09-how-to-print-pdf417-codes-with-escpos-php/2016-09-escpos-pdf417-05-options_hu_34e0f7bd666aa77b.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;208&#34;
		data-flex-basis=&#34;500px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-09-escpos-pdf417-05-options&#34;
      id=&#34;tabs-post-2016-09-escpos-pdf417-05-options-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2016-09-escpos-pdf417-05-options-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Change options
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Options&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$testStr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Testing 123&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$models&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;PDF417_STANDARD&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Standard&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;PDF417_TRUNCATED&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Truncated&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$models&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$model&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;pdf417Code&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testStr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;0.10&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$model&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$name\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2 id=&#34;notes&#34;&gt;Notes
&lt;/h2&gt;&lt;p&gt;To run the snippets, you need to initialise the printer, and define a &lt;code&gt;title()&lt;/code&gt; function to print headings, like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Demonstration of available options on the qrCode() command */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// ....
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Cut &amp;amp; close
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Escpos&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectPrintMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;MODE_DOUBLE_HEIGHT&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;MODE_DOUBLE_WIDTH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectPrintMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2015-04-howto-qrcodes-on-receipts-with-escpos-php&#34; &gt;the QR code post&lt;/a&gt;, I posted a fallback which used software rendering. As I don&amp;rsquo;t have a PHP-based PDF417 code library, you will need a printer which supports them to be blue to use these examples.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>What&#39;s in the AEC data feed, and how to use it</title>
        <link>https://mike42.me/blog/2016-06-aec-data-feed</link>
        <pubDate>Thu, 30 Jun 2016 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2016-06-aec-data-feed</guid>
        <description>&lt;p&gt;With an election coming up, it&amp;rsquo;s probably a good time to post some notes about using Australian election data feeds. This is mainly aimed at any interested programmers who have a use for this sort of data.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve left out any example code here, as what you write will be specific to how you use the data.&lt;/p&gt;
&lt;h2 id=&#34;overview&#34;&gt;Overview
&lt;/h2&gt;&lt;p&gt;The AEC publishes results on election night, by simply posting zipped files on an FTP server every few minutes. The detailed documentation is at &lt;a class=&#34;link&#34; href=&#34;http://www.aec.gov.au/media/mediafeed/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;aec.gov.au&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I have experimented with loading the data into a database during a recent by-election with some success. The data model that I assembled for this was:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-06-aec-data-feed/2016-06-data-model-aec-feed.png&#34;
	width=&#34;1130&#34;
	height=&#34;842&#34;
	srcset=&#34;https://mike42.me/blog/2016-06-aec-data-feed/2016-06-data-model-aec-feed_hu_9b48b406414c8041.png 480w, https://mike42.me/blog/2016-06-aec-data-feed/2016-06-data-model-aec-feed_hu_4a8371f56dee5bae.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;134&#34;
		data-flex-basis=&#34;322px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;You will be able to locate many electoral concepts in this data model, as &lt;strong&gt;candidates&lt;/strong&gt; with a particular &lt;strong&gt;affiliation&lt;/strong&gt; receive votes (&lt;strong&gt;contest&lt;/strong&gt; eachother) at different &lt;strong&gt;polling places&lt;/strong&gt; for a seat in one of the &lt;strong&gt;houses&lt;/strong&gt;. This maps to the more extensive XML format to extract the fields that I was most interested in mapping.&lt;/p&gt;
&lt;h2 id=&#34;getting-the-data&#34;&gt;Getting the data
&lt;/h2&gt;&lt;p&gt;The FTP server is &lt;code&gt;mediafeed.aec.gov.au&lt;/code&gt;, and it accepts anonymous login on election night.&lt;/p&gt;
&lt;p&gt;Here you will find a numbered folder for the night&amp;rsquo;s election. Within this, there is a lot of repetition, so you can ignore most of the files straight away. The sub-folders that I suggest loading are &lt;strong&gt;Detailed/LightProgress&lt;/strong&gt; and &lt;strong&gt;Detailed/Preload&lt;/strong&gt;. For example, in a past election, the file layout was:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;18126/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;18126/Detailed
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;18126/Detailed/LightProgress
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;18126/Detailed/LightProgress/aec-mediafeed-Detailed-LightProgress-18126-20150919194400.zip
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;18126/Detailed/LightProgress/aec-mediafeed-Detailed-LightProgress-18126-20150919194527.zip
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;18126/Detailed/LightProgress/aec-mediafeed-Detailed-LightProgress-18126-20150919194702.zip
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;18126/Detailed/LightProgress/aec-mediafeed-Detailed-LightProgress-18126-20150911140244.zip
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;18126/Detailed/LightProgress/aec-mediafeed-Detailed-LightProgress-18126-20150919195500.zip
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;18126/Detailed/LightProgress/...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;18126/Detailed/Preload
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;18126/Detailed/Preload/aec-mediafeed-Detailed-Preload-18126-20150911140243.zip
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;loading-the-data&#34;&gt;Loading the data
&lt;/h2&gt;&lt;p&gt;Start with the &lt;strong&gt;Preload&lt;/strong&gt; data. This zip file is available first, and contains the candidate names, polling places, event details, and an initial (zeroed-out) results feed. Using a custom script and a schema like the one I&amp;rsquo;ve posted above, you will be able to import this into your database.&lt;/p&gt;
&lt;p&gt;Next, the &lt;strong&gt;LightProgress&lt;/strong&gt; feed updates will start being added every few minutes from 7pm. These Zip files contain a small piece of XML, each one superseding older files.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve cut down one of these files as an example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;utf-8&amp;#34;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;&amp;lt;MediaFeed&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Id=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;e9334806-990e-4773-8b00-7d74fa58b6af&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Created=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;2015-09-19T19:55:00&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;SchemaVersion=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;3&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;EmlVersion=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;5&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;xmlns=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;http://www.aec.gov.au/xml/schema/mediafeed&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;xmlns:eml=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;urn:oasis:names:tc:evs:schema:eml&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;xmlns:ds=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;http://www.w3.org/2000/09/xmldsig#&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;xmlns:xal=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;urn:oasis:names:tc:ciq:xsdschema:xAL:2.0&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;xmlns:xnl=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;urn:oasis:names:tc:ciq:xsdschema:xNL:2.0&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;xmlns:ts=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;urn:oasis:names:tc:evs:schema:eml:ts&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;xmlns:xs=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;http://www.w3.org/2001/XMLSchema-instance&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;xs:schemaLocation=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;http://www.aec.gov.au/xml/schema/mediafeed ../Schema/AEC/aec-mediafeed-results-v3-0.xsd&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;ManagingAuthority&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;lt;eml:AuthorityIdentifier&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Id=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;AEC&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;Australian Electoral Commission&lt;span class=&#34;nt&#34;&gt;&amp;lt;/eml:AuthorityIdentifier&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;/ManagingAuthority&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;MessageLanguage&amp;gt;&lt;/span&gt;en&lt;span class=&#34;nt&#34;&gt;&amp;lt;/MessageLanguage&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;MessageGenerator&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;lt;Name&amp;gt;&lt;/span&gt;Virtual Tally Room&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;lt;Environment&amp;gt;&lt;/span&gt;PROD&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Environment&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;lt;Site&amp;gt;&lt;/span&gt;CDC&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Site&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;lt;Server&amp;gt;&lt;/span&gt;DB02&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Server&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;lt;Platform&amp;gt;&lt;/span&gt;x64&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Platform&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;lt;Version&amp;gt;&lt;/span&gt;9.2.0.28493&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;/MessageGenerator&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;Cycle&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Created=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;2015-09-19T19:54:47&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;37f177b4-ab20-4073-be85-0edefa5c8e96&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Cycle&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;Results&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Phase=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;ElectionNight&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Verbosity=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;LightProgress&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Granularity=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Detailed&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;lt;eml:EventIdentifier&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Id=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;18126&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;lt;eml:EventName&amp;gt;&lt;/span&gt;Canning By-election&lt;span class=&#34;nt&#34;&gt;&amp;lt;/eml:EventName&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;lt;/eml:EventIdentifier&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;lt;Election&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;lt;eml:ElectionIdentifier&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Id=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;H&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;lt;eml:ElectionName&amp;gt;&lt;/span&gt;House of Representatives By-election for the division of Canning&lt;span class=&#34;nt&#34;&gt;&amp;lt;/eml:ElectionName&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;lt;eml:ElectionCategory&amp;gt;&lt;/span&gt;ByElection&lt;span class=&#34;nt&#34;&gt;&amp;lt;/eml:ElectionCategory&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;lt;/eml:ElectionIdentifier&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;lt;House&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;lt;Contests&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;nt&#34;&gt;&amp;lt;Contest&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Projected=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nt&#34;&gt;&amp;lt;eml:ContestIdentifier&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Id=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;236&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;nt&#34;&gt;&amp;lt;eml:ContestName&amp;gt;&lt;/span&gt;Canning&lt;span class=&#34;nt&#34;&gt;&amp;lt;/eml:ContestName&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nt&#34;&gt;&amp;lt;/eml:ContestIdentifier&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nt&#34;&gt;&amp;lt;Enrolment&amp;gt;&lt;/span&gt;112809&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Enrolment&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nt&#34;&gt;&amp;lt;FirstPreferences&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;PollingPlacesReturned=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;PollingPlacesExpected=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;53&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;nt&#34;&gt;&amp;lt;Candidate&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nt&#34;&gt;&amp;lt;eml:CandidateIdentifier&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Id=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;25424&amp;#34;&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nt&#34;&gt;&amp;lt;BallotPosition&amp;gt;&lt;/span&gt;1&lt;span class=&#34;nt&#34;&gt;&amp;lt;/BallotPosition&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nt&#34;&gt;&amp;lt;Elected&amp;gt;&lt;/span&gt;false&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Elected&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;MatchedHistoric=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nt&#34;&gt;&amp;lt;VotesByType&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Ordinary&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Absent&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Provisional&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;PrePoll&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Postal&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nt&#34;&gt;&amp;lt;/VotesByType&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;nt&#34;&gt;&amp;lt;/Candidate&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;c&#34;&gt;&amp;lt;!-- (other candidates, ghost candidates) --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;nt&#34;&gt;&amp;lt;Formal&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;MatchedHistoric=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nt&#34;&gt;&amp;lt;VotesByType&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Ordinary&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Absent&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Provisional&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;PrePoll&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Postal&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nt&#34;&gt;&amp;lt;/VotesByType&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;nt&#34;&gt;&amp;lt;/Formal&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;nt&#34;&gt;&amp;lt;Informal&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;MatchedHistoric=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nt&#34;&gt;&amp;lt;VotesByType&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Ordinary&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Absent&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Provisional&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;PrePoll&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Postal&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nt&#34;&gt;&amp;lt;/VotesByType&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;nt&#34;&gt;&amp;lt;/Informal&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;nt&#34;&gt;&amp;lt;Total&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;MatchedHistoric=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nt&#34;&gt;&amp;lt;VotesByType&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Ordinary&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Absent&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Provisional&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;PrePoll&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                  &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Type=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Postal&amp;#34;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nt&#34;&gt;&amp;lt;/VotesByType&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;nt&#34;&gt;&amp;lt;/Total&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nt&#34;&gt;&amp;lt;/FirstPreferences&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nt&#34;&gt;&amp;lt;TwoCandidatePreferred&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Restricted=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;PollingPlacesReturned=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;PollingPlacesExpected=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;53&amp;#34;&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nt&#34;&gt;&amp;lt;TwoPartyPreferred&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;nt&#34;&gt;&amp;lt;Coalition&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nt&#34;&gt;&amp;lt;CoalitionIdentifier&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Id=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;nt&#34;&gt;&amp;lt;/Coalition&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;nt&#34;&gt;&amp;lt;Coalition&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nt&#34;&gt;&amp;lt;CoalitionIdentifier&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Id=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nt&#34;&gt;&amp;lt;Votes&amp;gt;&lt;/span&gt;0&lt;span class=&#34;nt&#34;&gt;&amp;lt;/Votes&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;nt&#34;&gt;&amp;lt;/Coalition&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nt&#34;&gt;&amp;lt;/TwoPartyPreferred&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nt&#34;&gt;&amp;lt;PollingPlaces&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;nt&#34;&gt;&amp;lt;PollingPlace&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nt&#34;&gt;&amp;lt;PollingPlaceIdentifier&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Id=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;7467&amp;#34;&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nt&#34;&gt;&amp;lt;FirstPreferences&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nt&#34;&gt;&amp;lt;TwoCandidatePreferred&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;Restricted=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;nt&#34;&gt;&amp;lt;/PollingPlace&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;c&#34;&gt;&amp;lt;!-- (other polling places, ghost candidates) --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nt&#34;&gt;&amp;lt;/PollingPlaces&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;nt&#34;&gt;&amp;lt;/Contest&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;lt;/Contests&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;lt;/House&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;lt;/Election&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;lt;/Results&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;&amp;lt;/MediaFeed&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;spatial-data&#34;&gt;Spatial data
&lt;/h2&gt;&lt;p&gt;You can also download electorate boundaries as spatial data &lt;a class=&#34;link&#34; href=&#34;http://www.aec.gov.au/electorates/gis/index.htm&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;here&lt;/a&gt; to back any visualisations of the results.&lt;/p&gt;
&lt;p&gt;The locations of polling places are already encoded in the &lt;strong&gt;Preload&lt;/strong&gt; data file.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to set up Docker containers in Travis CI</title>
        <link>https://mike42.me/blog/2016-06-how-to-set-up-docker-containers-in-travis-ci</link>
        <pubDate>Thu, 23 Jun 2016 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2016-06-how-to-set-up-docker-containers-in-travis-ci</guid>
        <description>&lt;p&gt;This post outlines a method for using Docker for testing on Travis CI. It may be useful to you if you are a web application developer who uses GitHub.&lt;/p&gt;
&lt;p&gt;I use this setup in my web-based &lt;a href=&#34;https://github.com/mike42/word-puzzles&#34;&gt;word puzzle generator&lt;/a&gt;, so that every change is spun up and tested with a web browser before it is merged.&lt;/p&gt;
&lt;p&gt;I got the idea for writing this from a few lines in the &lt;a href=&#34;https://docs.docker.com/compose/overview/&#34;&gt;docker-compose&lt;/a&gt; documentation, which suggested that Docker is an easy way to perform automated testing over a running application:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ docker-compose up -d
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ./run_tests
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ docker-compose down
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This snippet was missing some setup and an example app, but these three lines do all the heavy lifting.&lt;/p&gt;
&lt;h3&gt;The Docker setup&lt;/h3&gt;
In order to focus on the Docker setup, I made a server which simply responds to TCP requests on port 5000 with the text &#34;Hello World&#34;.
&lt;p&gt;This file is called &lt;tt&gt;server.sh&lt;/tt&gt;, and sits in a directory called &lt;tt&gt;foo_server&lt;/tt&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; true&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;# Send &amp;#39;Hello World&amp;#39; to anybody who connects on port 5000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello World&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; nc -l &lt;span class=&#34;m&#34;&gt;5000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Alongside it, I added a &lt;tt&gt;Dockerfile&lt;/tt&gt; to instruct docker to execute this tiny &amp;lsquo;application&amp;rsquo; in a container, after installing the dependencies. This machine is built from the Docker-official &lt;a href=&#34;https://hub.docker.com/_/debian/&#34;&gt;Debian image&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;FROM&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; debian&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ADD&lt;/span&gt; . /usr/share/test-server&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;WORKDIR&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; /usr/share/test-server&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;RUN&lt;/span&gt; apt-get update &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get install --assume-yes netcat-openbsd&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;CMD&lt;/span&gt; ./server.sh&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Lastly, a &lt;tt&gt;.dockerignore&lt;/tt&gt; file is used to avoid loading the &lt;tt&gt;Dockerfile&lt;/tt&gt; to the container:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# Ignore docker files
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Dockerfile
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.dockerignore
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the directory above, a simple test script, &lt;tt&gt;test.sh&lt;/tt&gt; is used to see that the server is returning the expected output:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -e
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;expected&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello World&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;actual&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;nc -v localhost 5000&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Expecting: &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$expected&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Server says: &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$actual&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$expected&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; !&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$actual&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Test failed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Test passed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Alongside the test file, a file called &lt;tt&gt;docker-compose.yml&lt;/tt&gt; instructs Docker to create a container out of the &lt;tt&gt;foo_server&lt;/tt&gt; example, and forward port &lt;tt&gt;127.0.0.1:5000&lt;/tt&gt; to it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;2&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;services&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;foo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;build&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;foo_server&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;     &lt;/span&gt;- &lt;span class=&#34;s2&#34;&gt;&amp;#34;5000:5000&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;foo_1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To try it out for yourself, you need a relatively recent version of Docker and docker-compose. The versions provided in Debian were not new enough to execute the examples, but the Docker project provides &lt;a class=&#34;link&#34; href=&#34;https://apt.dockerproject.org/repo/dists/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;repos&lt;/a&gt; containing newer builds for Debian &amp;amp; Ubuntu. For my distro, the install was:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;curl -sSL &amp;#34;https://get.docker.com/gpg&amp;#34; | sudo -E apt-key add -
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;echo &amp;#34;deb https://apt.dockerproject.org/repo debian-stretch main&amp;#34; | sudo tee -a /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get update
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install docker-engine
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo pip install docker-compose
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The versions this got me were docker 1.11.2, and docker-compose 1.7.1. Straight after the install, I could deploy &amp;amp; test an example locally:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ docker-compose up --build -d
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ./test.sh
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ docker-compose down
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;the-ci-setup&#34;&gt;The CI setup
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;ll assume that if you&amp;rsquo;re reading this, you are familiar with the basics of &lt;a class=&#34;link&#34; href=&#34;https://docs.travis-ci.org&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Travis CI&lt;/a&gt;. The large block of code below is the &lt;tt&gt;.travis.yml&lt;/tt&gt; file to set up the test machine, then execute the tests against a container.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nn&#34;&gt;---&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Use Ubuntu &amp;#39;trusty&amp;#39; distribution&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;sudo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;required&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;dist&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;trusty&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;install&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Update docker-engine using Ubuntu &amp;#39;trusty&amp;#39; apt repo&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;    curl -sSL &amp;#34;https://get.docker.com/gpg&amp;#34; |
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;     sudo -E apt-key add -&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;    echo &amp;#34;deb https://apt.dockerproject.org/repo ubuntu-trusty main&amp;#34; |
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;     sudo tee -a /etc/apt/sources.list&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;sudo apt-get update&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;    sudo apt-get -o Dpkg::Options::=&amp;#34;--force-confdef&amp;#34; \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;     -o Dpkg::Options::=&amp;#34;--force-confold&amp;#34; --assume-yes install docker-engine&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;docker version&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Update docker-compose via pip&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;sudo pip install docker-compose&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;docker-compose version&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;before_script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;docker-compose up --build -d&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;./test.sh&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;after_script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;docker-compose down&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;...&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This uses Travis CI&amp;rsquo;s &lt;tt&gt;trusty&lt;/tt&gt; distribution, which at the time of writing is the newest stable build platform available on Travis CI. This shipped an outdated version of Docker, which had to be installed over. Because the existing Docker was configured, I had to override a debconf prompt, which is why the &lt;a class=&#34;link&#34; href=&#34;https://docs.travis-ci.com/user/installing-dependencies/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;apt addon&lt;/a&gt; syntax was not used to set up dependencies.&lt;/p&gt;
&lt;h2 id=&#34;result&#34;&gt;Result
&lt;/h2&gt;&lt;p&gt;The build result for each commit is displayed in Travis CI:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-06-how-to-set-up-docker-containers-in-travis-ci/2016-06-ci-result-1.png&#34;
	width=&#34;1042&#34;
	height=&#34;289&#34;
	srcset=&#34;https://mike42.me/blog/2016-06-how-to-set-up-docker-containers-in-travis-ci/2016-06-ci-result-1_hu_63060dfeaf3196d1.png 480w, https://mike42.me/blog/2016-06-how-to-set-up-docker-containers-in-travis-ci/2016-06-ci-result-1_hu_61bf2d2f3a519c36.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;360&#34;
		data-flex-basis=&#34;865px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Under this, the output of the passing test script is shown, showing what has been set up:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-06-how-to-set-up-docker-containers-in-travis-ci/2016-06-ci-result-2.png&#34;
	width=&#34;956&#34;
	height=&#34;220&#34;
	srcset=&#34;https://mike42.me/blog/2016-06-how-to-set-up-docker-containers-in-travis-ci/2016-06-ci-result-2_hu_59a5b38a8b7a10ff.png 480w, https://mike42.me/blog/2016-06-how-to-set-up-docker-containers-in-travis-ci/2016-06-ci-result-2_hu_f7b09dd757b1067a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;434&#34;
		data-flex-basis=&#34;1042px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;using-this-setup-in-practice&#34;&gt;Using this setup in practice
&lt;/h2&gt;&lt;p&gt;Moving this from a demo setup to a real setup would be fairly simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Replace the installation with a real software stack&lt;/li&gt;
&lt;li&gt;Replace the server run with a command to serve the application (such as a Apache HTTP, Tomcat or Node)&lt;/li&gt;
&lt;li&gt;Replace the tests with real tests (such as Cucumber or Selenium).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/word-puzzles&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;example in the pre-amble&lt;/a&gt; installs a LAMP stack and tests it with Selenium in its CI build.&lt;/p&gt;
&lt;p&gt;If your application is a bit larger, your only extra complexity will come from running multiple containers with &lt;tt&gt;docker-compose&lt;/tt&gt;.&lt;/p&gt;
&lt;h2 id=&#34;get-the-code&#34;&gt;Get the code
&lt;/h2&gt;&lt;p&gt;All of these scripts in a working CI example are available on GitHub: &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/minimal-docker-ci&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/minimal-docker-ci&lt;/a&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Print larger or smaller text on a thermal receipt printer</title>
        <link>https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer</link>
        <pubDate>Thu, 16 Jun 2016 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer</guid>
        <description>&lt;p&gt;If you print to a thermal receipt printer which support the ESC/POS protocol, then you can format the receipts to make larger or smaller text.&lt;/p&gt;
&lt;p&gt;If this is your first time reading about ESC/POS, have a read of &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/what-is-escpos-and-how-do-i-use-it&#34; &gt;What is ESC/POS, and how do I use it?&lt;/a&gt;. Some of these text size examples are borrowed from there, while some are new for this blog post.&lt;/p&gt;
&lt;h2 id=&#34;smaller-text&#34;&gt;Smaller text
&lt;/h2&gt;


&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-06-text-size-01&#34;
      id=&#34;tabs-post-2016-06-text-size-01-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2016-06-text-size-01-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/2014-11-escpos-07.png&#34;
	width=&#34;600&#34;
	height=&#34;124&#34;
	srcset=&#34;https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/2014-11-escpos-07_hu_c73840273b02f81c.png 480w, https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/2014-11-escpos-07_hu_204a247ef42570b1.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;483&#34;
		data-flex-basis=&#34;1161px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-06-text-size-01&#34;
      id=&#34;tabs-post-2016-06-text-size-01-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2016-06-text-size-01-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Fonts (many printers do not have a &amp;#39;Font C&amp;#39;) */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$fonts&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;FONT_A&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;FONT_B&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;FONT_C&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$fonts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setFont&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$fonts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;The quick brown fox jumps over the lazy dog&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setFont&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Reset
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-06-text-size-01&#34;
      id=&#34;tabs-post-2016-06-text-size-01-2&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2016-06-text-size-01-2&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Hexdump
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000000  1b 40 1b 4d 00 54 68 65  20 71 75 69 63 6b 20 62  |.@.M.The quick b|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000010  72 6f 77 6e 20 66 6f 78  20 6a 75 6d 70 73 20 6f  |rown fox jumps o|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000020  76 65 72 20 74 68 65 20  6c 61 7a 79 20 64 6f 67  |ver the lazy dog|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000030  0a 1b 4d 01 54 68 65 20  71 75 69 63 6b 20 62 72  |..M.The quick br|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000040  6f 77 6e 20 66 6f 78 20  6a 75 6d 70 73 20 6f 76  |own fox jumps ov|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000050  65 72 20 74 68 65 20 6c  61 7a 79 20 64 6f 67 0a  |er the lazy dog.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000060  1b 4d 02 54 68 65 20 71  75 69 63 6b 20 62 72 6f  |.M.The quick bro|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000070  77 6e 20 66 6f 78 20 6a  75 6d 70 73 20 6f 76 65  |wn fox jumps ove|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000080  72 20 74 68 65 20 6c 61  7a 79 20 64 6f 67 0a 1b  |r the lazy dog..|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000090  4d 00 1d 56 41 03                                 |M..VA.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000096
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2 id=&#34;change-height--width&#34;&gt;Change height &amp;amp; width
&lt;/h2&gt;


&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-06-text-size-02&#34;
      id=&#34;tabs-post-2016-06-text-size-02-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2016-06-text-size-02-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/2016-06-textsize-00.png&#34;
	width=&#34;300&#34;
	height=&#34;116&#34;
	srcset=&#34;https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/2016-06-textsize-00_hu_9ca054ab0915b12e.png 480w, https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/2016-06-textsize-00_hu_ef60910492fa53cb.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;258&#34;
		data-flex-basis=&#34;620px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-06-text-size-02&#34;
      id=&#34;tabs-post-2016-06-text-size-02-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2016-06-text-size-02-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Text of various (in-proportion) sizes */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Change height &amp;amp; width&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setTextSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectPrintMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;MODE_EMPHASIZED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectPrintMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Reset
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-06-text-size-02&#34;
      id=&#34;tabs-post-2016-06-text-size-02-2&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2016-06-text-size-02-2&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Hexdump
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000000  1b 40 1b 21 08 0a 43 68  61 6e 67 65 20 68 65 69  |.@.!..Change hei|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000010  67 68 74 20 26 20 77 69  64 74 68 0a 1b 21 00 1d  |ght &amp;amp; width..!..|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000020  21 00 31 1d 21 11 32 1d  21 22 33 1d 21 33 34 1d  |!.1.!.2.!&amp;#34;3.!34.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000030  21 44 35 1d 21 55 36 1d  21 66 37 1d 21 77 38 0a  |!D5.!U6.!f7.!w8.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000040  1d 56 41 03                                       |.VA.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000044
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2 id=&#34;change-width-only-height4&#34;&gt;Change width only (height=4)
&lt;/h2&gt;


&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-06-text-size-03&#34;
      id=&#34;tabs-post-2016-06-text-size-03-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2016-06-text-size-03-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/2016-06-textsize-01.png&#34;
	width=&#34;300&#34;
	height=&#34;78&#34;
	srcset=&#34;https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/2016-06-textsize-01_hu_82ba83a9aa8d83cb.png 480w, https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/2016-06-textsize-01_hu_3e0b6523d51341cd.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;384&#34;
		data-flex-basis=&#34;923px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-06-text-size-03&#34;
      id=&#34;tabs-post-2016-06-text-size-03-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2016-06-text-size-03-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Width changing only */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Change width only (height=4):&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setTextSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectPrintMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;MODE_EMPHASIZED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectPrintMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Reset
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-06-text-size-03&#34;
      id=&#34;tabs-post-2016-06-text-size-03-2&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2016-06-text-size-03-2&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Hexdump
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000000  1b 40 1b 21 08 0a 43 68  61 6e 67 65 20 77 69 64  |.@.!..Change wid|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000010  74 68 20 6f 6e 6c 79 20  28 68 65 69 67 68 74 3d  |th only (height=|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000020  34 29 3a 0a 1b 21 00 1d  21 03 31 1d 21 13 32 1d  |4):..!..!.1.!.2.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000030  21 23 33 1d 21 33 34 1d  21 43 35 1d 21 53 36 1d  |!#3.!34.!C5.!S6.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000040  21 63 37 1d 21 73 38 0a  1d 56 41 03              |!c7.!s8..VA.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0000004c
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2 id=&#34;change-height-only-width4&#34;&gt;Change height only (width=4)
&lt;/h2&gt;


&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-06-text-size-04&#34;
      id=&#34;tabs-post-2016-06-text-size-04-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2016-06-text-size-04-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/2016-06-textsize-02.png&#34;
	width=&#34;300&#34;
	height=&#34;111&#34;
	srcset=&#34;https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/2016-06-textsize-02_hu_56bf94a427390779.png 480w, https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/2016-06-textsize-02_hu_c91b90c2f1593ec2.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;270&#34;
		data-flex-basis=&#34;648px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-06-text-size-04&#34;
      id=&#34;tabs-post-2016-06-text-size-04-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2016-06-text-size-04-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Height changing only */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Change height only (width=4):&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setTextSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectPrintMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;MODE_EMPHASIZED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectPrintMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Reset
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-06-text-size-04&#34;
      id=&#34;tabs-post-2016-06-text-size-04-2&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2016-06-text-size-04-2&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Hexdump
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000000  1b 40 1b 21 08 0a 43 68  61 6e 67 65 20 68 65 69  |.@.!..Change hei|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000010  67 68 74 20 6f 6e 6c 79  20 28 77 69 64 74 68 3d  |ght only (width=|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000020  34 29 3a 0a 1b 21 00 1d  21 30 31 1d 21 31 32 1d  |4):..!..!01.!12.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000030  21 32 33 1d 21 33 34 1d  21 34 35 1d 21 35 36 1d  |!23.!34.!45.!56.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000040  21 36 37 1d 21 37 38 0a  1d 56 41 03              |!67.!78..VA.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0000004c
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2 id=&#34;very-narrow-font&#34;&gt;Very narrow font
&lt;/h2&gt;


&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-06-text-size-05&#34;
      id=&#34;tabs-post-2016-06-text-size-05-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2016-06-text-size-05-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/2016-06-textsize-03.png&#34;
	width=&#34;300&#34;
	height=&#34;127&#34;
	srcset=&#34;https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/2016-06-textsize-03_hu_6e35c37fa2e44801.png 480w, https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/2016-06-textsize-03_hu_c8e74c9fff5f9cd8.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;236&#34;
		data-flex-basis=&#34;566px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-06-text-size-05&#34;
      id=&#34;tabs-post-2016-06-text-size-05-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2016-06-text-size-05-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Very narrow text */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Very narrow text:&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setTextSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;The quick brown fox jumps over the lazy dog.&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectPrintMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;MODE_EMPHASIZED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectPrintMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Reset
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-06-text-size-05&#34;
      id=&#34;tabs-post-2016-06-text-size-05-2&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2016-06-text-size-05-2&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Hexdump
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000000  1b 40 1b 21 08 0a 56 65  72 79 20 6e 61 72 72 6f  |.@.!..Very narro|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000010  77 20 74 65 78 74 3a 0a  1b 21 00 1d 21 07 54 68  |w text:..!..!.Th|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000020  65 20 71 75 69 63 6b 20  62 72 6f 77 6e 20 66 6f  |e quick brown fo|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000030  78 20 6a 75 6d 70 73 20  6f 76 65 72 20 74 68 65  |x jumps over the|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000040  20 6c 61 7a 79 20 64 6f  67 2e 0a 1d 56 41 03     | lazy dog...VA.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0000004f
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2 id=&#34;very-wide-font&#34;&gt;Very wide font
&lt;/h2&gt;


&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-06-text-size-06&#34;
      id=&#34;tabs-post-2016-06-text-size-06-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2016-06-text-size-06-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/2016-06-textsize-04.png&#34;
	width=&#34;300&#34;
	height=&#34;40&#34;
	srcset=&#34;https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/2016-06-textsize-04_hu_a4ea1c7fe78bdbca.png 480w, https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/2016-06-textsize-04_hu_8e43614c8f416315.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;750&#34;
		data-flex-basis=&#34;1800px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-06-text-size-06&#34;
      id=&#34;tabs-post-2016-06-text-size-06-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2016-06-text-size-06-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Very flat text */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Very wide text:&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setTextSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello world!&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectPrintMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;MODE_EMPHASIZED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectPrintMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Reset
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-06-text-size-06&#34;
      id=&#34;tabs-post-2016-06-text-size-06-2&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2016-06-text-size-06-2&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Hexdump
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000000  1b 40 1b 21 08 0a 56 65  72 79 20 77 69 64 65 20  |.@.!..Very wide |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000010  74 65 78 74 3a 0a 1b 21  00 1d 21 30 48 65 6c 6c  |text:..!..!0Hell|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000020  6f 20 77 6f 72 6c 64 21  0a 1d 56 41 03           |o world!..VA.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0000002d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2 id=&#34;largest-possible-font&#34;&gt;Largest possible font
&lt;/h2&gt;


&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-06-text-size-07&#34;
      id=&#34;tabs-post-2016-06-text-size-07-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2016-06-text-size-07-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/2016-06-textsize-05.png&#34;
	width=&#34;300&#34;
	height=&#34;211&#34;
	srcset=&#34;https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/2016-06-textsize-05_hu_d7d44b9bf39d2035.png 480w, https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/2016-06-textsize-05_hu_c3fd36376d067747.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;142&#34;
		data-flex-basis=&#34;341px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-06-text-size-07&#34;
      id=&#34;tabs-post-2016-06-text-size-07-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2016-06-text-size-07-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Very large text */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Largest possible text:&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setTextSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;world!&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectPrintMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;MODE_EMPHASIZED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectPrintMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Reset
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2016-06-text-size-07&#34;
      id=&#34;tabs-post-2016-06-text-size-07-2&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2016-06-text-size-07-2&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Hexdump
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000000  1b 40 1b 21 08 0a 4c 61  72 67 65 73 74 20 70 6f  |.@.!..Largest po|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000010  73 73 69 62 6c 65 20 74  65 78 74 3a 0a 1b 21 00  |ssible text:..!.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000020  1d 21 77 48 65 6c 6c 6f  0a 77 6f 72 6c 64 21 0a  |.!wHello.world!.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000030  1d 56 41 03                                       |.VA.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000034
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2 id=&#34;double-height-and-doule-width&#34;&gt;Double-height and doule-width
&lt;/h2&gt;&lt;p&gt;There are also commands which specifically &lt;em&gt;double&lt;/em&gt; the width and height. These overlap with the commands covered here, but you can find them in the &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;escpos-php&lt;/a&gt; documentation.&lt;/p&gt;
&lt;h2 id=&#34;full-example&#34;&gt;Full example
&lt;/h2&gt;&lt;p&gt;These examples were authored for &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;escpos-php&lt;/a&gt;, a PHP printer driver for thermal receipt printers. The full file ships as an example with the driver, and outputs a block of ESC/POS code which can be sent a printer to give the below output.&lt;/p&gt;
&lt;h3 id=&#34;receipt&#34;&gt;Receipt
&lt;/h3&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/f4218f44-395a-11e5-8079-25472c5ad340.jpg&#34;
	width=&#34;300&#34;
	height=&#34;694&#34;
	srcset=&#34;https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/f4218f44-395a-11e5-8079-25472c5ad340_hu_344adf4b352372cc.jpg 480w, https://mike42.me/blog/2016-06-print-larger-or-smaller-text-on-a-thermal-receipt-printer/f4218f44-395a-11e5-8079-25472c5ad340_hu_347532bf84af7ddc.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;43&#34;
		data-flex-basis=&#34;103px&#34;
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;php-code&#34;&gt;PHP code
&lt;/h3&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * This print-out shows how large the available font sizes are. It is included
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * separately due to the amount of text it prints.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;php://stdout&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Initialize */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;initialize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Text of various (in-proportion) sizes */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Change height &amp;amp; width&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setTextSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Width changing only */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Change width only (height=4):&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setTextSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Height changing only */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Change height only (width=4):&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setTextSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Very narrow text */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Very narrow text:&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setTextSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;The quick brown fox jumps over the lazy dog.&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Very flat text */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Very wide text:&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setTextSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello world!&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Very large text */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Largest possible text:&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setTextSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;world!&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectPrintMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;MODE_EMPHASIZED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectPrintMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Reset
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;other-formatting&#34;&gt;Other formatting?
&lt;/h2&gt;&lt;p&gt;If text size is not what you&amp;rsquo;re after, then you can find similar examples in other posts I&amp;rsquo;ve tagged &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/tag/escpos&#34; &gt;escpos&lt;/a&gt;.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to compile a C&#43;&#43;11 app on Travis CI</title>
        <link>https://mike42.me/blog/2016-06-how-to-compile-a-c11-app-on-travis-ci</link>
        <pubDate>Thu, 09 Jun 2016 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2016-06-how-to-compile-a-c11-app-on-travis-ci</guid>
        <description>&lt;p&gt;I have recently been adding Travis CI builds to &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;code that I host on GitHub&lt;/a&gt;, so that I don&amp;rsquo;t need to host my own build infrastructure.&lt;/p&gt;
&lt;p&gt;To users, this just means that there is a green badge at the top of the README, but not much else:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-06-how-to-compile-a-c11-app-on-travis-ci/passing.svg_.png&#34;
	width=&#34;90&#34;
	height=&#34;20&#34;
	srcset=&#34;https://mike42.me/blog/2016-06-how-to-compile-a-c11-app-on-travis-ci/passing.svg__hu_9de465d9ee18a9f1.png 480w, https://mike42.me/blog/2016-06-how-to-compile-a-c11-app-on-travis-ci/passing.svg__hu_3643682b7b52ac70.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;450&#34;
		data-flex-basis=&#34;1080px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;To build &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/missile&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;a simple&lt;/a&gt; C++ project, I added in this &lt;code&gt;.travis.yml&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;langauge&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;cpp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;sudo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;addons&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;apt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;packages&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;libusb-1.0-0-dev&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;make&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Unfortunately the default build tools are ancient on this infrastructure, which uses Ubuntu Precise (12.04):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ make
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;g++ src/missile.cpp examples/basic-sync/basic-sync.cpp -o bin/basic-sync -lpthread -lusb-1.0 -std&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;c++11 -Wall
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cc1plus: error: unrecognized &lt;span class=&#34;nb&#34;&gt;command&lt;/span&gt; line option ‘-std&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;c++11’
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cc1plus: error: unrecognized &lt;span class=&#34;nb&#34;&gt;command&lt;/span&gt; line option ‘-std&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;c++11’
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2&gt;Option 1: Update the toolchain&lt;/h2&gt;
&lt;p&gt;There is some structures you can use to install an extra repository and some named packages, instead of using &lt;code&gt;apt-get&lt;/code&gt; directly.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;langauge&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;cpp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;sudo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;addons&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;apt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;sources&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;ubuntu-toolchain-r-test&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;packages&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;gcc-4.8&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;g++-4.8&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;libusb-1.0-0-dev&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;make&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Because the old version was still installed, I had to refer to the exact version in the &lt;code&gt;Makefile&lt;/code&gt;, as in:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;g++-4.8 src/missile.cpp examples/basic-sync/basic-sync.cpp -o bin/basic-sync -lpthread -lusb-1.0 -std&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;c++11 -Wall
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2&gt;Option 2: Update the platform&lt;/h2&gt;
&lt;p&gt;You can also change to a more recent Ubuntu distribution. Presumably Ubuntu Precise is only the default because existing builds use it.&lt;/p&gt;
&lt;p&gt;If you need to build C++11 apps on Travis CI, then builds will work under Ubuntu Trusty (14.04), which happens to be the newest distribution currently available:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;langauge&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;cpp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;sudo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;required&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;dist&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;trusty&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;addons&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;apt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;packages&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;libusb-1.0-0-dev&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;make&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>How to edit emulator flags in Android Studio</title>
        <link>https://mike42.me/blog/2016-05-how-to-edit-emulator-flags-in-android-studio</link>
        <pubDate>Thu, 26 May 2016 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2016-05-how-to-edit-emulator-flags-in-android-studio</guid>
        <description>&lt;p&gt;I&amp;rsquo;ve recently updated to the new IntelliJ-based Android studio 2.1.&lt;/p&gt;
&lt;p&gt;I ran into some issues attempting to launch a &amp;ldquo;hello world&amp;rdquo; project in the emulator, which I&amp;rsquo;m writing up here for the benefit of others.&lt;/p&gt;
&lt;p&gt;For context, I run Debian GNU/Linux Jessie on an AMD64 box, with Radeon graphics card, using the free drivers.&lt;/p&gt;
&lt;h2 id=&#34;the-opengl-error&#34;&gt;The OpenGL error
&lt;/h2&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-05-how-to-edit-emulator-flags-in-android-studio/2016-05-22-android-1.png&#34;
	width=&#34;837&#34;
	height=&#34;390&#34;
	srcset=&#34;https://mike42.me/blog/2016-05-how-to-edit-emulator-flags-in-android-studio/2016-05-22-android-1_hu_30a3695bbbf5b88d.png 480w, https://mike42.me/blog/2016-05-how-to-edit-emulator-flags-in-android-studio/2016-05-22-android-1_hu_2b581b535bdecb41.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;214&#34;
		data-flex-basis=&#34;515px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;When attempting to launch a simple project with the emulator, the emulator died with the following message:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Cannot launch AVD in emulator.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Output:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;libGL error: unable to load driver: radeonsi_dri.so
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;libGL error: driver pointer missing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;libGL error: failed to load driver: radeonsi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;libGL error: unable to load driver: swrast_dri.so
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;libGL error: failed to load driver: swrast
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;X Error of failed request:  GLXBadContext
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Major opcode of failed request:  155 (GLX)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Minor opcode of failed request:  6 (X_GLXIsDirect)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Serial number of failed request:  49
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Current serial number in output stream:  48
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;libGL error: unable to load driver: radeonsi_dri.so
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;libGL error: driver pointer missing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;libGL error: failed to load driver: radeonsi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;libGL error: unable to load driver: swrast_dri.so
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;libGL error: failed to load driver: swrast
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;X Error of failed request:  GLXBadContext
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Major opcode of failed request:  155 (GLX)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Minor opcode of failed request:  6 (X_GLXIsDirect)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Serial number of failed request:  49
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Current serial number in output stream:  48
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;libGL error: unable to load driver: radeonsi_dri.so
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;libGL error: driver pointer missing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;libGL error: failed to load driver: radeonsi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;libGL error: unable to load driver: swrast_dri.so
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;libGL error: failed to load driver: swrast
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;X Error of failed request:  BadValue (integer parameter out of range for operation)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Major opcode of failed request:  155 (GLX)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Minor opcode of failed request:  24 (X_GLXCreateNewContext)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Value in failed request:  0x0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Serial number of failed request:  33
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;emulator: WARNING: VM heap size set below hardware specified minimum of 228MB
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;emulator: WARNING: Setting VM heap size to 384MB
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Current serial number in output stream:  34
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;QObject::~QObject: Timers cannot be stopped from another thread
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The console logs that the command being executed is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;home&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mike&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Android&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Sdk&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tools&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;emulator&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;netdelay&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;none&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;netspeed&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;full&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;avd&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Nexus_5X_API_23&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;fixing-on-the-command-line&#34;&gt;Fixing on the command-line
&lt;/h2&gt;&lt;h3 id=&#34;things-that-didnt-work&#34;&gt;Things that didn&amp;rsquo;t work
&lt;/h3&gt;&lt;p&gt;Installing more libraries via &lt;code&gt;apt-get&lt;/code&gt; did not help.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install libstdc++6 xserver-xorg-video-radeon
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pre-loading libraries also didn&amp;rsquo;t solve the issue.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;LD_PRELOAD&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/usr/lib64/libstdc++.so.6&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;home&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mike&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Android&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Sdk&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tools&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;emulator&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;netdelay&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;none&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;netspeed&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;full&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;avd&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Nexus_5X_API_23&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Attempting to understand LibGL&amp;rsquo;s debug output was also not particularly useful in my case.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;LIBGL_DEBUG&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;verbose&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;home&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mike&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Android&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Sdk&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tools&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;emulator&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;netdelay&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;none&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;netspeed&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;full&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;avd&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Nexus_5X_API_23&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;what-did-work-for-me&#34;&gt;What did work for me
&lt;/h3&gt;&lt;p&gt;The solution turned out to be this specific flag:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ./emulator -help | grep libstdc++
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    -use-system-libs               Use system libstdc++ instead of bundled one
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So launching the emulator from the CLI worked for me, using this command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;home&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mike&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Android&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Sdk&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tools&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;emulator&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;netdelay&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;none&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;netspeed&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;full&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;avd&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Nexus_5X_API_23&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;use&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;system&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;libs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;fixing-in-the-ide&#34;&gt;Fixing in the IDE
&lt;/h2&gt;&lt;p&gt;So this was fantastic progress, but without being able to launch this emulator from Android Studio, the development environment wasn&amp;rsquo;t really &lt;em&gt;integrated&lt;/em&gt; yet.&lt;/p&gt;
&lt;p&gt;Apparently there &lt;a class=&#34;link&#34; href=&#34;&#34; &gt;used to be a feature&lt;/a&gt; for adding command-line flags to the emulator, but this is now gone.&lt;/p&gt;
&lt;p&gt;So, adapting &lt;a class=&#34;link&#34; href=&#34;http://stackoverflow.com/questions/33909062/no-emulator-tab-in-edit-configurations-in-android-studio&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;a post here&lt;/a&gt;, I jumped in and replaced the &lt;code&gt;emulator&lt;/code&gt; binary with a wrapper to inject some flags.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ &lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; ~/Android/Sdk/tools/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ mv emulator emulator.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ touch emulator
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ chmod +x emulator
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I then opened up the emulator in a text editor and punched in this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -ex
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$0&lt;/span&gt;.0 &lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt; -use-system-libs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;result&#34;&gt;Result
&lt;/h2&gt;&lt;p&gt;Success!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-05-how-to-edit-emulator-flags-in-android-studio/2016-05-22-android-2.png&#34;
	width=&#34;1429&#34;
	height=&#34;947&#34;
	srcset=&#34;https://mike42.me/blog/2016-05-how-to-edit-emulator-flags-in-android-studio/2016-05-22-android-2_hu_2b4aa667a2a15470.png 480w, https://mike42.me/blog/2016-05-how-to-edit-emulator-flags-in-android-studio/2016-05-22-android-2_hu_1b9e19db25a861ff.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;150&#34;
		data-flex-basis=&#34;362px&#34;
	
&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Blog domain migrated</title>
        <link>https://mike42.me/blog/2016-05-domain-move</link>
        <pubDate>Tue, 03 May 2016 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2016-05-domain-move</guid>
        <description>&lt;p&gt;As of today, this blog has now moved to a shorter domain name: &lt;a class=&#34;link&#34; href=&#34;https://mike42.me&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://mike42.me&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hopefully, none of the content got lost in the move!&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Quick guide: Running stock Debian on the Raspberry Pi 2</title>
        <link>https://mike42.me/blog/2016-01-rpi2-debian</link>
        <pubDate>Fri, 22 Apr 2016 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2016-01-rpi2-debian</guid>
        <description>&lt;p&gt;At the time of writing, the &amp;lsquo;Raspbian&amp;rsquo; port of Debian is often used on the Raspberry Pi. It was created to match the CPU architecture, for better performance. These reasons don&amp;rsquo;t apply to the newer Raspberry Pi 2, so if you&amp;rsquo;re a Debian desktop or server user, you can do away with the fork and just run Debian Jessie &lt;code&gt;armhf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The info from Debian is: &lt;a class=&#34;link&#34; href=&#34;https://wiki.debian.org/RaspberryPi2&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://wiki.debian.org/RaspberryPi2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A bit more background about why this only applies to the Raspberry Pi 2:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Raspberry Pi 1 uses ARMv6 chipset with hard floats
&lt;ul&gt;
&lt;li&gt;The Debian &lt;code&gt;armhf&lt;/code&gt; port requires ARMv7&lt;/li&gt;
&lt;li&gt;The Debian &lt;code&gt;armel&lt;/code&gt; port doesn&amp;rsquo;t use hard floats, so is unnecessarily slow on the Pi.&lt;/li&gt;
&lt;li&gt;So Raspbian was created for the Raspberry Pi 1&amp;rsquo;s ARMv6 w/ hard-floats, and gets the most juice out of the CPU on the Raspberry Pi 1.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The Raspberry Pi 2 uses ARMv7 with hard floats, so the Debian &lt;code&gt;armhf&lt;/code&gt; port is fine.&lt;/li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;install-the-image&#34;&gt;Install the image
&lt;/h2&gt;&lt;p&gt;The image is linked to from this page:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;http://sjoerd.luon.net/posts/2015/02/debian-jessie-on-rpi2/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://sjoerd.luon.net/posts/2015/02/debian-jessie-on-rpi2/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I will assume that your machine has an SD card slot. To find the device name, list out disks and look for one of the correct size, which appears when you plug in the card:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;df
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Download a copy of the image, extract it out, and &lt;code&gt;dd&lt;/code&gt; the file on to the card:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wget -c https://images.collabora.co.uk/rpi2/jessie-rpi2-20150705.img.gz
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gunzip jessie-rpi2-20150705.img.gz 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo dd if=jessie-rpi2-20150705.img of=/dev/sdX bs=4M
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo sync
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;umount /media/$USER/*
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Plug in the Raspberry pi, and then log in. If you are using SSH, then &lt;code&gt;arp-scan&lt;/code&gt; is a good tool to pick up devices on the network:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install arp-scan
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo arp-scan -l
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ssh root@x.y.z.w
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Configure pi- Things like screen resolution and HDMI go here:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cd /boot/firmware/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nano config.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Perform a software upgrade:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nano /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get update
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get dist-upgrade
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Start fixing security defaults. Remember that this is not a clean install, so start by setting your own passwords:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;passwd
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Check that there are no other accounts with passwords set:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat /etc/shadow
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Regenerate all SSH Server keys (commands from &lt;a class=&#34;link&#34; href=&#34;http://www.softec.lu/site/DevelopersCorner/HowToRegenerateNewSsh&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;here&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ssh-keygen -f /etc/ssh/ssh_host_ecdsa_key -N &amp;#39;&amp;#39; -t ecdsa -b 521
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ssh-keygen -f /etc/ssh/ssh_host_dsa_key -N &amp;#39;&amp;#39; -t dsa
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ssh-keygen -f /etc/ssh/ssh_host_rsa_key -N &amp;#39;&amp;#39; -t rsa
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Lastly, generate some locales:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo locale-gen en_US en_US.UTF-8 en_GB en_GB.UTF-8
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>How to resize a Windows VM image with virt-resize</title>
        <link>https://mike42.me/blog/2016-03-how-to-resize-a-windows-vm-image-with-virt-resize</link>
        <pubDate>Thu, 10 Mar 2016 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2016-03-how-to-resize-a-windows-vm-image-with-virt-resize</guid>
        <description>&lt;p&gt;I recently had a Windows 7 Virtual Machine stored on an undersized qcow2 file. This post steps through the simplest way that I know to produce a new, bigger disk and expand the filesystem onto it.&lt;/p&gt;
&lt;h2 id=&#34;empty-out-the-empty-space&#34;&gt;Empty out the empty space
&lt;/h2&gt;&lt;p&gt;Because the guest VM is stored on a QCOW2 file, we can recover un-used space on disk by zeroing it out now. Download the &lt;a class=&#34;link&#34; href=&#34;https://technet.microsoft.com/en-us/sysinternals/sdelete.aspx&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;sdelete&lt;/a&gt; utility from Microsoft and run it on the system.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sdelete -z
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One this is done, power off the guest.&lt;/p&gt;
&lt;p&gt;Assuming the host is linux, you need the `qemu-utls` and `libguestfs-tools` packages to follow these steps. On Debian-&lt;/p&gt; 
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;apt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;install&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libguestfs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tools&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;utls&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Move the VM image to a new filename and inspect it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mv windows.img windows.img.bak
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;file&lt;/code&gt; command indicates that the disk is about 30GB expanded.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ file windows.img.bak 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;windows.img.bak: QEMU QCOW Image (v3), 32212254720 bytes
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;qemu-img&lt;/code&gt; command shows that the disk is 83% full:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ qemu-img check windows.img.bak 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;No errors were found on the image.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;411337/491520 = 83.69% allocated, 5.66% fragmented, 0.00% compressed clusters
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Image end offset: 26961969152
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Check out your FS names, note that &lt;code&gt;/dev/sda2&lt;/code&gt; is the disk we want to up-size in this case&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ virt-filesystems -a windows.img -l
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Name       Type        VFS   Label            Size         Parent
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/dev/sda1  filesystem  ntfs  System Reserved  104857600    -
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/dev/sda2  filesystem  ntfs  -                32105299968  -
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;make-a-new-bigger-disk-image&#34;&gt;Make a new, bigger disk image
&lt;/h2&gt;&lt;p&gt;Create a new disk of the desired size. In my case, 50G is sufficient:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ qemu-img create -f qcow2 windows.img 50G
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Formatting &amp;#39;windows.img&amp;#39;, fmt=qcow2 size=53687091200 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;file&lt;/code&gt; command shows that this new empty disk image is larger than the old image.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ file windows.img
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;windows.img: QEMU QCOW Image (v3), 53687091200 bytes
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Copy the old disk to the new one. The &lt;code&gt;--expand&lt;/code&gt; option names a partition which will be grown to fill the extra space.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;virt-resize --expand /dev/sda2 windows.img.bak windows.img
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;virt-resize&lt;/code&gt; command shows a progress bar while it works, and zero-blocks will be reclaimed as a result of the output format:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-03-how-to-resize-a-windows-vm-image-with-virt-resize/2016-04-disk01.png&#34;
	width=&#34;1284&#34;
	height=&#34;391&#34;
	srcset=&#34;https://mike42.me/blog/2016-03-how-to-resize-a-windows-vm-image-with-virt-resize/2016-04-disk01_hu_ac042786780b5a8d.png 480w, https://mike42.me/blog/2016-03-how-to-resize-a-windows-vm-image-with-virt-resize/2016-04-disk01_hu_99796b683020ff50.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;328&#34;
		data-flex-basis=&#34;788px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The final line of output suggests holding on to your backup until you&amp;rsquo;ve checked it, which is wise:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Resize operation completed with no errors.  Before deleting the old disk, carefully check that the resized disk boots and works correctly.&amp;rdquo;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Check that the new disk is valid and contains partitions at the expected size:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ virt-filesystems -a windows.img -l
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Name       Type        VFS   Label            Size         Parent
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/dev/sda1  filesystem  ntfs  System Reserved  104857600    -
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/dev/sda2  filesystem  ntfs  -                53579939840  -
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;boot-up-the-guest&#34;&gt;Boot up the guest
&lt;/h2&gt;&lt;p&gt;When the machine boots up, you may get a disk check prompt. Because the console I was using triggered the &amp;lsquo;Press any key to cancel&amp;rsquo; prompt, I had to reboot and leave the console disconnected in order for the check to start.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-03-how-to-resize-a-windows-vm-image-with-virt-resize/2016-04-disk02.png&#34;
	width=&#34;640&#34;
	height=&#34;480&#34;
	srcset=&#34;https://mike42.me/blog/2016-03-how-to-resize-a-windows-vm-image-with-virt-resize/2016-04-disk02_hu_cc863a46a88c8f72.png 480w, https://mike42.me/blog/2016-03-how-to-resize-a-windows-vm-image-with-virt-resize/2016-04-disk02_hu_7882a4f6cd0af05d.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-03-how-to-resize-a-windows-vm-image-with-virt-resize/2016-04-disk03.png&#34;
	width=&#34;640&#34;
	height=&#34;480&#34;
	srcset=&#34;https://mike42.me/blog/2016-03-how-to-resize-a-windows-vm-image-with-virt-resize/2016-04-disk03_hu_1c17bb716d6e8547.png 480w, https://mike42.me/blog/2016-03-how-to-resize-a-windows-vm-image-with-virt-resize/2016-04-disk03_hu_8fd46202851b8a50.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;After booting, the &lt;code&gt;C:\&lt;/code&gt; drive should display at its new size:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-03-how-to-resize-a-windows-vm-image-with-virt-resize/2016-04-disk04.png&#34;
	width=&#34;793&#34;
	height=&#34;477&#34;
	srcset=&#34;https://mike42.me/blog/2016-03-how-to-resize-a-windows-vm-image-with-virt-resize/2016-04-disk04_hu_d4f0c8ed054a1753.png 480w, https://mike42.me/blog/2016-03-how-to-resize-a-windows-vm-image-with-virt-resize/2016-04-disk04_hu_2097da3ba4b30408.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;166&#34;
		data-flex-basis=&#34;398px&#34;
	
&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Convert a PC to a HTPC with Debian and Kodi</title>
        <link>https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi</link>
        <pubDate>Thu, 25 Feb 2016 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi</guid>
        <description>&lt;p&gt;I recently converted an old workstation to run as a home-theatre PC (HTPC). I&amp;rsquo;ve noted down the setup here for others who are making an installation like this. Some steps depend on using a radeon chipset, and will need to be adjusted for your computer.&lt;/p&gt;
&lt;h2 id=&#34;hardware&#34;&gt;Hardware
&lt;/h2&gt;&lt;p&gt;First up, Desktop &amp;rsquo;towers&amp;rsquo; are not a good form-factor for sitting in TV cabinets. If your PC is this sort of size, then source a small form-factor case and power supply, and load the computer&amp;rsquo;s components into it:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-htpc.png&#34;
	width=&#34;514&#34;
	height=&#34;296&#34;
	srcset=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-htpc_hu_23e23a3adca0b256.png 480w, https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-htpc_hu_3b4052ed78cb595a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;173&#34;
		data-flex-basis=&#34;416px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I also used a &lt;a class=&#34;link&#34; href=&#34;http://www.logitech.com/en-au/product/wireless-touch-keyboard-k400r&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Logitech k400r&lt;/a&gt; keyboard and mouse for wireless input.&lt;/p&gt;
&lt;h2 id=&#34;install-debian-and-apps&#34;&gt;Install Debian and apps
&lt;/h2&gt;&lt;p&gt;Write the latest copy of Debian Stable to a CD or flash drive (this is version 8.3 at time of writing), and install it on the computer. Check &amp;ldquo;Debian Desktop environment&amp;rdquo; / GNOME during setup.&lt;/p&gt;
&lt;p&gt;After installation, open a terminal, and type &amp;ldquo;su&amp;rdquo; to get root privileges.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;su
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Edit the software sources.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nano /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Update this to include &amp;lsquo;contrib&amp;rsquo; and &amp;rsquo;non-free&amp;rsquo;, as well as &amp;lsquo;jessie-backports&amp;rsquo;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb http://ftp.us.debian.org/debian/ jessie main contrib non-free
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb-src http://ftp.us.debian.org/debian/ jessie main contrib non-free
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb http://security.debian.org/ jessie/updates main contrib non-free
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb-src http://security.debian.org/ jessie/updates main contrib non-free
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# jessie-updates, previously known as &amp;#39;volatile&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb http://ftp.us.debian.org/debian/ jessie-updates main contrib non-free
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb-src http://ftp.us.debian.org/debian/ jessie-updates main contrib non-free
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# jessie-backports
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb http://ftp.us.debian.org/debian/ jessie-backports main contrib non-free
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb-src http://ftp.us.debian.org/debian/ jessie-backports main contrib non-free
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Update sources and install Kodi:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install --install-suggests kodi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Also install the firmware packages that you may need.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install firmware-linux-free firmware-amd-graphics
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;tweaks&#34;&gt;Tweaks
&lt;/h2&gt;&lt;h3 id=&#34;sudo&#34;&gt;Sudo
&lt;/h3&gt;&lt;p&gt;sudo allows you to run commands as root from your regular user account. Install the package and add yourself to the &lt;code&gt;sudo&lt;/code&gt; group:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install sudo
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;usermod -a -G sudo mike
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To apply the change, log out and back in again. The rest of this guide assumes you are logged in as yourself, and will use sudo where necessary.&lt;/p&gt;
&lt;h3 id=&#34;auto-start-kodi&#34;&gt;Auto-start Kodi
&lt;/h3&gt;&lt;p&gt;Open the tweak tool, and locate the list of startup programs.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gnome-tweak-tool
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add Kodi to the list, log out, log in, and Kodi will launch automatically.&lt;/p&gt;
&lt;h3 id=&#34;auto-login&#34;&gt;Auto-login
&lt;/h3&gt;&lt;p&gt;For a PC attached to a TV, user permissions are not so importnat, so set the user to log in automatically.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo nano /etc/gdm3/daemon.conf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Un-comment this block and enter your username:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# Enabling automatic login
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#  AutomaticLoginEnable = true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#  AutomaticLogin = user1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;plymouth-start-up-screen&#34;&gt;Plymouth start-up screen
&lt;/h3&gt;&lt;p&gt;Install &lt;code&gt;plymouth&lt;/code&gt; and configure &lt;code&gt;grub&lt;/code&gt; to change the Debian boot sequence (a menu with timeout, followed by lots of text) into a graphical splash screen. This takes a bit of configuration.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install plymouth
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Set it up according to &lt;a class=&#34;link&#34; href=&#34;https://wiki.debian.org/plymouth&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;these instructions&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo nano /etc/initramfs-tools/modules
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Set &lt;code&gt;drm&lt;/code&gt; correctly for your chipset:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# KMS
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;drm
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;radeon modeset=1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Configure grub.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo nano /etc/default/grub
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Set these options.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;GRUB_TIMEOUT=0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;GRUB_CMDLINE_LINUX_DEFAULT=&amp;#34;quiet splash&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;GRUB_GFXMODE=1920x1080
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Update grub, set the theme in Plymouth:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo update-grub2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo /usr/sbin/plymouth-set-default-theme --list
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo /usr/sbin/plymouth-set-default-theme joy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run &lt;code&gt;update-initramfs&lt;/code&gt; to apply the changes&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo update-initramfs -u
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;samba&#34;&gt;Samba
&lt;/h3&gt;&lt;p&gt;Samba will let you share folders over your network. A basic folder with guest read/write is simple to set up:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install nautilus-share samba libpam-smbpass winbind
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo usermod -a -G sambashare mike
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Log out, and back in to apply the group change, and then share the Public folder over the network by right-clicking on it and opening the &amp;ldquo;Sharing Options&amp;rdquo;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-samba-share.png&#34;
	width=&#34;386&#34;
	height=&#34;402&#34;
	srcset=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-samba-share_hu_10b4bec427732a0e.png 480w, https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-samba-share_hu_d558857e27a741ab.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;96&#34;
		data-flex-basis=&#34;230px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Gnome will warn that the folder as shared if you open it:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-samba-shared.png&#34;
	width=&#34;769&#34;
	height=&#34;458&#34;
	srcset=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-samba-shared_hu_6f16c790fcf24eaa.png 480w, https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-samba-shared_hu_9ef1611767bca420.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;167&#34;
		data-flex-basis=&#34;402px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Test the setup by typing &lt;code&gt;smb://localhost&lt;/code&gt; into the address bar:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-samba-test.png&#34;
	width=&#34;838&#34;
	height=&#34;498&#34;
	srcset=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-samba-test_hu_d160b333a27fba3.png 480w, https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-samba-test_hu_71b5de1f77eeff47.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;168&#34;
		data-flex-basis=&#34;403px&#34;
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;overscan-correction&#34;&gt;Overscan correction
&lt;/h3&gt;&lt;p&gt;In my case, I was able to set the TV to treat the input as a &amp;ldquo;PC&amp;rdquo; input. If that doesn&amp;rsquo;t work for you, then use &lt;code&gt;xrandr&lt;/code&gt; in a login script:&lt;/p&gt;
&lt;p&gt;Find the name of your input:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;xrandr --query
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Set underscan (get the horizontal and vertical values by trial and error):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;xrandr --output HDMI-0 --set underscan on
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;xrandr --output HDMI-0 --set &lt;span class=&#34;s2&#34;&gt;&amp;#34;underscan hborder&amp;#34;&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;32&lt;/span&gt; --set &lt;span class=&#34;s2&#34;&gt;&amp;#34;underscan vborder&amp;#34;&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;kodi-plugins&#34;&gt;Kodi plugins
&lt;/h3&gt;&lt;p&gt;Add these as needed. The Australian catchup TV plugins repository from GitHub worked well.&lt;/p&gt;
&lt;h3 id=&#34;kodi-rss&#34;&gt;Kodi RSS
&lt;/h3&gt;&lt;p&gt;The RSS feed shows Kodi updates by default, and is part of your user profile.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-feed-file.png&#34;
	width=&#34;908&#34;
	height=&#34;334&#34;
	srcset=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-feed-file_hu_b8559c577aefcb00.png 480w, https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-feed-file_hu_d89a0f9f32ad43ca.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;271&#34;
		data-flex-basis=&#34;652px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Edit the configuration file, and adjust the paths to your news sources of choice.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-feed.png&#34;
	width=&#34;848&#34;
	height=&#34;648&#34;
	srcset=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-feed_hu_69b14751717fb77b.png 480w, https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-feed_hu_6a3b70ed19dc6550.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;130&#34;
		data-flex-basis=&#34;314px&#34;
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;boot-speed&#34;&gt;Boot speed
&lt;/h3&gt;&lt;p&gt;Readahead is the tool of choice for boot speed optimisation. Install it, and reboot.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install readahead
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo touch  /.readahead_collect
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo reboot
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;desktop-apps&#34;&gt;Desktop Apps
&lt;/h3&gt;&lt;p&gt;If you quit Kodi, you are dropped back to the GNOME desktop. These apps are simply to improve the desktop user experience.&lt;/p&gt;
&lt;h3 id=&#34;google-chrome&#34;&gt;Google Chrome
&lt;/h3&gt;&lt;p&gt;Download the &lt;code&gt;.deb&lt;/code&gt; file for Chrome from Google, install with &lt;code&gt;dpkg&lt;/code&gt;, and then clean up dependencies:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dpkg -i google-chrome-stable_current_amd64.deb 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get -f install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;firefox&#34;&gt;Firefox
&lt;/h3&gt;&lt;p&gt;Download and extract the Firefox for Linux tarball from Mozilla.&lt;/p&gt;
&lt;p&gt;Move it to &lt;code&gt;/usr/share&lt;/code&gt;, and change the owner to match other applications there.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mv firefox /usr/share/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; /usr/share/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ls -Ahl
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chown root:root firefox
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chown -R root:root firefox
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Find the main menu editor, and add Firefox to the menu.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-menu.png&#34;
	width=&#34;391&#34;
	height=&#34;253&#34;
	srcset=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-menu_hu_69a60e7ba94150af.png 480w, https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-menu_hu_44d5df53732e5b9f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;154&#34;
		data-flex-basis=&#34;370px&#34;
	
&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Name&lt;/strong&gt;: Firefox Web Browser&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Command&lt;/strong&gt;: /usr/share/firefox/firefox-bin&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Icon&lt;/strong&gt;: /usr/share/firefox/browser/icons/mozicon128.png&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-firefox-icon.png&#34;
	width=&#34;510&#34;
	height=&#34;221&#34;
	srcset=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-firefox-icon_hu_13954083ef9a1f82.png 480w, https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-firefox-icon_hu_2a77021fa728042e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;230&#34;
		data-flex-basis=&#34;553px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-firefox-menu.png&#34;
	width=&#34;677&#34;
	height=&#34;570&#34;
	srcset=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-firefox-menu_hu_a7e81ad65b8f0575.png 480w, https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-firefox-menu_hu_276ddd8d8a57336c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;118&#34;
		data-flex-basis=&#34;285px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Test the new icon by searching:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-ff.png&#34;
	width=&#34;456&#34;
	height=&#34;233&#34;
	srcset=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-ff_hu_ab5060999e02e3c9.png 480w, https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-ff_hu_41a81b1997ae9459.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;195&#34;
		data-flex-basis=&#34;469px&#34;
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;auto-clear-browser-profiles&#34;&gt;Auto-clear browser profiles
&lt;/h3&gt;&lt;p&gt;Because you don&amp;rsquo;t need a password to log in to the user account, you can add this as a bit of security so that your box won&amp;rsquo;t remember any passwords or sessions.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;crontab -e
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This job removes the Firefox and Chrome user profiles each boot.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;@reboot rm --preserve-root -Rf -- ~/.config/google-chrome ~/.cache/google-chrome ~/.mozilla/firefox ~/.cache/mozilla/firefox
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;vlc&#34;&gt;VLC
&lt;/h3&gt;&lt;p&gt;For file format support, best to have another media player:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install vlc
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;result&#34;&gt;Result
&lt;/h2&gt;&lt;p&gt;You should now have a PC which boots into Kodi for media and TV, and lets you quit into a desktop to browse the web or run regular desktop apps.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-kodi.png&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-kodi_hu_24cdefd493a8fec0.png 480w, https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-kodi_hu_3990104d649ca06e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-gnome.png&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-gnome_hu_c9faa92dee385292.png 480w, https://mike42.me/blog/2016-02-convert-a-pc-to-a-htpc-with-debian-and-kodi/2016-02-gnome_hu_457be358256be193.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;On the 1GB RAM / dual-core workstation, it still took around 45 seconds from the BIOS handing over control to Kodi being ready.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 2017-12-29&lt;/strong&gt;: Re-installing this setup on an SSD shortened the boot time to 21 seconds. This includes boot, login, and an application start.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to regenerate SSH client keys</title>
        <link>https://mike42.me/blog/2016-01-how-to-regenerate-ssh-client-keys</link>
        <pubDate>Fri, 22 Jan 2016 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2016-01-how-to-regenerate-ssh-client-keys</guid>
        <description>&lt;p&gt;Recently, a SSH client bug was discovered that &lt;a class=&#34;link&#34; href=&#34;https://www.qualys.com/2016/01/14/cve-2016-0777-cve-2016-0778/openssh-cve-2016-0777-cve-2016-0778.txt&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;could let the server read client private keys&lt;/a&gt; in some situations.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re affected, then follow these steps. Regular users of SSH may be familiar with the commands used.&lt;/p&gt;
&lt;h2 id=&#34;if-you-use-public-key-authentication&#34;&gt;If you use public key authentication
&lt;/h2&gt;&lt;p&gt;If you do use keys to authenticate, you should regenerate them. Start by backing up your old key. Assuming it&amp;rsquo;s at the default location, just use-&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ mv ~/.ssh/id_rsa ~/.ssh/id_rsa.old
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ mv ~/.ssh/id_rsa.pub ~/.ssh/id_rsa.pub.old
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, create or edit &lt;code&gt;~/.ssh/config&lt;/code&gt;, and add the following line. This disables the roaming feature, which was part of the problem:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;UseRoaming no
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Generate new keys:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ssh-keygen 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Generating public/private rsa key pair.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Enter file in which to save the key (/home/example/.ssh/id_rsa): 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Enter passphrase (empty for no passphrase): 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Enter same passphrase again: 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Your identification has been saved in /home/example/.ssh/id_rsa.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Your public key has been saved in /home/example/.ssh/id_rsa.pub.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now copy the new &lt;strong&gt;public key&lt;/strong&gt; over, using the old keys. You would normally use &lt;code&gt;ssh-copy-id&lt;/code&gt;, but it &lt;i&gt;adds&lt;/i&gt; keys rather than replacing them, which is why we need to do it manually:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;scp -i ~/.ssh/id_rsa.old ~/.ssh/id_rsa.pub user@example.com:/home/user/id_rsa.pub.new
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;SSH in with the old key:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ssh -i ~/.ssh/id_rsa.old
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Replace all current authorized keys with the newly generated one:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mv -f id_rsa.pub.new ~/.ssh/authorized_keys
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chmod 600 ~/.ssh/authorized_keys
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Logout, log back in with the new key to make sure it works, and you&amp;rsquo;re done.&lt;/p&gt;
&lt;h2 id=&#34;if-you-dont-use-public-keys&#34;&gt;If you don&amp;rsquo;t use public keys
&lt;/h2&gt;&lt;p&gt;If you don&amp;rsquo;t use keys for login, now could be a good time to start. Public-key authentication provides much stronger protection from brute force attacks, and also prevents the need for the server to be sent your password each time you log in.&lt;/p&gt;
&lt;p&gt;Create or edit &lt;code&gt;~/.ssh/config&lt;/code&gt; as above, and make sure it contains this line-&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;UseRoaming no
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Generate a keypair and add your public key to the server-&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ssh-keygen
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ssh-copy-id user@example.com
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Test it out:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ssh user@example.com
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At his point, you should disable password-based authentication in OpenSSH server. If you don&amp;rsquo;t control the server&amp;rsquo;s SSH configuration, then just set a good random password for your account to prevent it being brute-forced:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;openssl rand -base64 32
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat /dev/urandom | head -c32 | base64
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Set it on your account:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;passwd
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Update 2017-10-22&lt;/strong&gt;: Updated to correct errors in the commands.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Basic Cucumber feature testing</title>
        <link>https://mike42.me/blog/2016-01-basic-cucumber-feature-testing</link>
        <pubDate>Sat, 16 Jan 2016 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2016-01-basic-cucumber-feature-testing</guid>
        <description>&lt;p&gt;Cucumber is a Behaviour-Driven-Development (BDD) tool. You can use to automate the acceptance tests for your software systems. A real-world example of its use in a large application is the &lt;a class=&#34;link&#34; href=&#34;https://www.mediawiki.org/wiki/Quality_Assurance&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;MediaWiki QA&lt;/a&gt; process.&lt;/p&gt;
&lt;p&gt;This post will show you the steps to get it up-and-running to test a trivial app on a Unix (Mac, Linux) computer. I&amp;rsquo;ll assume that you already have Ruby installed.&lt;/p&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation
&lt;/h2&gt;&lt;p&gt;First up, install Cucumber&amp;rsquo;s Ruby implementation:&amp;lt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo gem install cucumber
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo gem install rspec
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you&amp;rsquo;re on Debian, you can also achieve this with &lt;code&gt;apt-get&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo apt-get install ruby-cucumber-core ruby-rspec
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The versions that I got from the install were-&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ruby --version
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ruby 2.2.3p173 (2015-08-18) [x86_64-linux-gnu]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cucumber --version
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2.3.0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;demo-project&#34;&gt;Demo project
&lt;/h2&gt;&lt;p&gt;Make a &amp;ldquo;hello world&amp;rdquo; project:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ mkdir cucumber-hello
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cd cucumber-hello/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One of the under-celebrated features of Cucumber is the quality of its error messages. Simply attempt to run it and you will be told what to do next:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cucumber
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;No such file or directory - features. You can use `cucumber --init` to get started.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Go ahead and run &lt;code&gt;cucumber --init&lt;/code&gt; as the program suggests:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cucumber --init
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  create   features
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  create   features/step_definitions
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  create   features/support
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  create   features/support/env.rb
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This has set up your project. In the same vein as Test-Driven Development (TDD), the usual practice is to write the tests before you code.&lt;/p&gt;
&lt;p&gt;Most programmers will be familiar with the expected output of a &amp;ldquo;Hello World&amp;rdquo; program. In Cucumber, this &amp;lsquo;feature&amp;rsquo; would be represented in Cucumber as:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Feature: Test
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Scenario: Hello
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    When I run the &amp;#34;hello-world&amp;#34; program
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    Then I should see &amp;#34;Hello World&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Save this definition to &lt;code&gt;features/hello.feature&lt;/code&gt; in the project directory and attempt to run Cucumber again:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cucumber
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Feature: Test
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Scenario: Hello                        # features/hello.feature:3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    When I run the &amp;#34;hello-world&amp;#34; program # features/hello.feature:4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    Then I should see &amp;#34;Hello World&amp;#34;      # features/hello.feature:5
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;1 scenario (1 undefined)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2 steps (2 undefined)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0m0.007s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;You can implement step definitions for undefined steps with these snippets:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;When(/^I run the &amp;#34;([^&amp;#34;]*)&amp;#34; program$/) do |arg1|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  pending # Write code here that turns the phrase above into concrete actions
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;end
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Then(/^I should see &amp;#34;([^&amp;#34;]*)&amp;#34;$/) do |arg1|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  pending # Write code here that turns the phrase above into concrete actions
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;end
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The output helpfully contains the skeleton code for writing the test steps in Ruby. Using this as a base, I implemented a test using the rspec &lt;a class=&#34;link&#34; href=&#34;https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;expectations syntax&lt;/a&gt;, to check if the &lt;a class=&#34;link&#34; href=&#34;https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/start-with-matcher&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;string starts with&lt;/a&gt; &amp;ldquo;Hello World&amp;rdquo;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;When(/^I run the &amp;#34;([^&amp;#34;]*)&amp;#34; program$/) do |cmd|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  @value = `./#{cmd}`  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;end
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Then(/^I should see &amp;#34;([^&amp;#34;]*)&amp;#34;$/) do |val|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  expect(@value).to start_with(val)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;end
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Save these steps to  &lt;code&gt;features/step_definitions/hello_steps.rb&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Finally, its time to code. Write up an implementation of &amp;ldquo;Hello World&amp;rdquo; in &lt;a class=&#34;link&#34; href=&#34;http://rosettacode.org/wiki/Hello_world/Text&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;basically any programming language&lt;/a&gt;, and save the output to an executable file called &lt;code&gt;hello-world&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;Using bash:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello World&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ chmod +x hello-world
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Manually testing:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ./hello-world
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Hello World
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Automatically testing with Cucumber confirms that the test criteria are met:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cucumber
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Feature: Test
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Scenario: Hello                        # features/hello.feature:3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    When I run the &amp;#34;hello-world&amp;#34; program # features/step_definitions/hello_steps.rb:1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    Then I should see &amp;#34;Hello World&amp;#34;      # features/step_definitions/hello_steps.rb:5
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;1 scenario (1 passed)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2 steps (2 passed)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0m0.016s
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now that you&amp;rsquo;ve completed these steps, you should have this project structure:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ find .
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./features
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./features/support
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./features/support/env.rb
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./features/step_definitions
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./features/step_definitions/hello_steps.rb
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./features/hello.feature
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./hello-world
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;next-steps&#34;&gt;Next steps
&lt;/h2&gt;&lt;p&gt;Our scenario for the Hello World program has users interfacing with the system entirely with non-interactive shell commands. Cucumber needs to be able to observe the external behaviour of your application, so your steps will end up including some powerful test libraries. Some that are used often are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Command-line: &lt;a class=&#34;link&#34; href=&#34;https://github.com/cucumber/aruba&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Aruba&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Web-based: &lt;a class=&#34;link&#34; href=&#34;https://github.com/jnicklas/capybara&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Capybara&lt;/a&gt; (back-ends include Selenium WebDriver, &lt;a class=&#34;link&#34; href=&#34;https://cucumber.io/docs/reference/browser-automation&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;tutorial here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Mobile: iOS &amp;amp; Android - &lt;a class=&#34;link&#34; href=&#34;http://calaba.sh/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Calabash&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>How to arrange pages for printing and cutting in LaTeX</title>
        <link>https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex</link>
        <pubDate>Fri, 08 Jan 2016 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex</guid>
        <description>&lt;p&gt;This post covers some LaTeX examples that I recently assembled for print-outs where multiple pages per sheet will be printed for cutting.&lt;/p&gt;
&lt;p&gt;First up, an example file. This is a document filled with random text, on C6 paper.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-latex&#34; data-lang=&#34;latex&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\documentclass&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;article&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\usepackage&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;[c6paper]&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;geometry&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\usepackage&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;lipsum&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\begin&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;document&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\section*&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Lorem Ipsum&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\lipsum&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;[1-11]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\end&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;document&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It renders like so:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/book-pages.png&#34;
	width=&#34;2693&#34;
	height=&#34;3827&#34;
	srcset=&#34;https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/book-pages_hu_a4f7973933a6efe8.png 480w, https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/book-pages_hu_d7d9810a74d136b5.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;70&#34;
		data-flex-basis=&#34;168px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;For the same example output in PDF format, see &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/book-pages.pdf&#34; &gt;book-pages.pdf&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;1x1-arrangement&#34;&gt;1x1 arrangement
&lt;/h2&gt;&lt;p&gt;Using the &lt;code&gt;crop&lt;/code&gt; package, you can wrap the output pages of your document in larger pages. Using the &lt;code&gt;\includepdf&lt;/code&gt; macro, these pages can be sourced from our example document.&lt;/p&gt;
&lt;p&gt;This example simply renders the document on larger pages, with crop marks displayed at the document edges.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-latex&#34; data-lang=&#34;latex&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\documentclass&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;article&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\usepackage&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;pdfpages&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Sum of dimensions of the pages. We are displaying 1x1 C6 (114 mm x 162mm) pages, which is where 114x162 comes from.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\usepackage&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;[paperheight=162mm,paperwidth=114mm]&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;geometry&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Include print/output paper size and orientation here, A4 portrait in this example (use &amp;#39;landscape&amp;#39; option for landscape)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\usepackage&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;[axes,cam,a4,pdftex,center]&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;crop&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\begin&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;document&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Restrict page range, and set arrangement of pages per sheet here.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\includepdf&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;[pages=-,nup=1x1,noautoscale]&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;book-pages.pdf&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\end&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;document&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This renders a single C6 page on A4, as below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/book-print-1x1.png&#34;
	width=&#34;4961&#34;
	height=&#34;7016&#34;
	srcset=&#34;https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/book-print-1x1_hu_87bd2cf840354958.png 480w, https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/book-print-1x1_hu_8f6a8f51f2d09c98.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;70&#34;
		data-flex-basis=&#34;169px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Alternatively see &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/book-print-1x1.pdf&#34; &gt;book-print-1x1.pdf&lt;/a&gt; for this output in PDF format.&lt;/p&gt;
&lt;h2 id=&#34;2x1-arrangement&#34;&gt;2x1 arrangement
&lt;/h2&gt;&lt;p&gt;To lay out two images side-by-side, we need to specify the size of the document we&amp;rsquo;re wrapping (which will be twice as wide as a single C6 page, and the height of a single C6 page), and also change the orientation of the outer paper to Landscape.&lt;/p&gt;
&lt;p&gt;The LaTeX code is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-latex&#34; data-lang=&#34;latex&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\documentclass&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;article&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\usepackage&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;pdfpages&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Sum of dimensions of the pages. We are displaying 2x1 C6 (114 mm x 162mm) pages, which is where 228x162 comes from.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\usepackage&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;[paperheight=162mm,paperwidth=228mm]&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;geometry&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Include print/output paper size and orientation here, A4 landscape in this example.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\usepackage&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;[axes,cam,a4,landscape,pdftex,center]&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;crop&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\begin&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;document&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Restrict page range, and set arrangement of pages per sheet here.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\includepdf&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;[pages=-,nup=2x1,noautoscale]&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;book-pages.pdf&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\end&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;document&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Which renders like this (click &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/book-print-2x1.pdf&#34; &gt;here&lt;/a&gt; for PDF):&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/book-print-2x1.png&#34;
	width=&#34;7016&#34;
	height=&#34;4961&#34;
	srcset=&#34;https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/book-print-2x1_hu_abc73db87c8cd1d4.png 480w, https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/book-print-2x1_hu_9f5d6bda909f299.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;141&#34;
		data-flex-basis=&#34;339px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;2x2-arrangement&#34;&gt;2x2 arrangement
&lt;/h2&gt;&lt;p&gt;In a similar way, we can slot four portrait C6 pages on to a piece of A4 portrait paper like so:&lt;/p&gt; 
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-latex&#34; data-lang=&#34;latex&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\documentclass&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;article&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\usepackage&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;pdfpages&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Sum of dimensions of the pages. We are displaying 2x2 C6 (114 mm x 162mm) pages, which is where 228x324 comes from.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\usepackage&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;[paperheight=324mm,paperwidth=228mm]&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;geometry&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Include print/output paper size and orientation here, A3 portrait in this example (use &amp;#39;landscape&amp;#39; option for landscape)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\usepackage&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;[axes,cam,a3,pdftex,center]&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;crop&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\begin&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;document&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Restrict page range, and set arrangement of pages per sheet here.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\includepdf&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;[pages=-,nup=2x2,noautoscale]&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;book-pages.pdf&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\end&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;document&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Which renders as (click &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/book-print-2x2.pdf&#34; &gt;here&lt;/a&gt; for PDF):&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/book-print-2x2.png&#34;
	width=&#34;5846&#34;
	height=&#34;8268&#34;
	srcset=&#34;https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/book-print-2x2_hu_94373d31b9246308.png 480w, https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/book-print-2x2_hu_16488dbde87be652.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;70&#34;
		data-flex-basis=&#34;169px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;more-complex-arrangement-name-tags&#34;&gt;More complex arrangement: Name tags
&lt;/h2&gt;&lt;p&gt;All of the above setups share one thing in common: they have 2 or fewer items on each side, meaning that the half-way axis lines could be used to show where each page ends.&lt;/p&gt;
&lt;p&gt;If you are printing many small items, you might fit more than two in a direction, and need to add more axis lines so that you know where to cut!&lt;/p&gt;
&lt;p&gt;Here is an example PDF which creates tiny name tags. All names here are randomly generated.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-latex&#34; data-lang=&#34;latex&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\documentclass&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;article&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Custom page size
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\usepackage&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;[margin=4mm,paperheight=30mm,paperwidth=60mm]&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;geometry&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Macro for a name tag
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\newcommand&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;[2]&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\begin&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;center&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;~&lt;span class=&#34;k&#34;&gt;\\\textbf&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\Large&lt;/span&gt;#1&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\\&lt;/span&gt;~&lt;span class=&#34;k&#34;&gt;\\\em&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;#2&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\end&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;center&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\clearpage&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\begin&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;document&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Make some name tags for a conference
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Names generated via www.generatedata.com/
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Flynn Craig&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;ExampleCorp&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Daniel Cash&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;ExampleCorp&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Griffith Durham&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;ExampleCorp&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Sean Washington&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;ExampleCorp&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;James Simon&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;ExampleCorp&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Aidan Cotton&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;ExampleCorp&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Wing Sanders&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;ExampleCorp&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Dean Wilcox&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;ExampleCorp&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Jerome Flynn&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;FooCorp&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Leonard Steele&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;FooCorp&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Zane Pratt&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;FooCorp&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Andrew Hartman&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;FooCorp&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Roth Mccullough&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;FooCorp&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Fritz Taylor&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;Quux Ltd&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Beau Bray&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;Quux Ltd&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Duncan Hampton&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;Quux Ltd&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Daquan Witt&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;Quux Ltd&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Wylie Heath&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;Quux Ltd&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Thaddeus Payne&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;Quux Ltd&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Carson Ayala&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;Quux Ltd&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Oleg Olson&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;Quux Ltd&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Herrod Gillespie&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;Bar University&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Jonas Wyatt&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;Bar University&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Mannix Patrick&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;Bar University&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Cain Ferguson&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;Bar University&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Nasim Mendez&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;Bar University&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Emery Bennett&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;Bar University&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Oscar Bennett&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;Bar University&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;William Neal&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;Bar University&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Dieter Cochran&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;Bar University&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\tag&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Bert Schultz&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;Bar University&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\end&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;document&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The above example renders a single name tag per page like this (click &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/labels.pdf&#34; &gt;here&lt;/a&gt; for PDF):&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/labels.png&#34;
	width=&#34;1417&#34;
	height=&#34;709&#34;
	srcset=&#34;https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/labels_hu_74c2f1b63662d01c.png 480w, https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/labels_hu_c958e940ea5cfe9a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;199&#34;
		data-flex-basis=&#34;479px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Now, the trick is that &lt;code&gt;crop&lt;/code&gt; is hard-coded to show axis lines only at the half-way points, so take a copy of &lt;code&gt;crop.sty&lt;/code&gt; called &lt;code&gt;crop-3x7.sty&lt;/code&gt; and find this block:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-latex&#34; data-lang=&#34;latex&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\newcommand*\CROP&lt;/span&gt;@marks&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;%
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;\CROP&lt;/span&gt;@setmarkcolor
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\CROP&lt;/span&gt;@user@b
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\CROP&lt;/span&gt;@ulc&lt;span class=&#34;k&#34;&gt;\null\hfill\CROP&lt;/span&gt;@@@info&lt;span class=&#34;k&#34;&gt;\CROP&lt;/span&gt;@upedge&lt;span class=&#34;k&#34;&gt;\hfill\null\CROP&lt;/span&gt;@urc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\vfill&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\CROP&lt;/span&gt;@ledge&lt;span class=&#34;k&#34;&gt;\hfill\CROP&lt;/span&gt;@redge
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\vfill&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\CROP&lt;/span&gt;@llc&lt;span class=&#34;k&#34;&gt;\null\hfill\CROP&lt;/span&gt;@loedge&lt;span class=&#34;k&#34;&gt;\hfill\null\CROP&lt;/span&gt;@lrc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The block uses &lt;code&gt;\vfill&lt;/code&gt; and &lt;code&gt;\hfill&lt;/code&gt; to make even spaces.&lt;/p&gt;
&lt;p&gt;Edit the file to include more axis lines, like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-latex&#34; data-lang=&#34;latex&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;%% &amp;#39;crop-3x7&amp;#39; is not a real package for general use, it is an example only!
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;%%
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;%% It is a modified version of the &amp;#39;crop&amp;#39; package, for rendering
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;%% additonal axis marks as cutting aids.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Changed package name here-
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\ProvidesPackage&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;crop-3x7&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;[2016/01/03 v2.0 crop marks 3x7 (mf)]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\newcommand*\CROP&lt;/span&gt;@marks&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;%
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;c&#34;&gt;% Changed from one axis on each side to 2 axes on top/lower edge, 6 on each side, for printing 3x7 panels per this example. 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;\CROP&lt;/span&gt;@setmarkcolor
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\CROP&lt;/span&gt;@user@b
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\CROP&lt;/span&gt;@ulc&lt;span class=&#34;k&#34;&gt;\null\hfill\CROP&lt;/span&gt;@@@info&lt;span class=&#34;k&#34;&gt;\CROP&lt;/span&gt;@upedge&lt;span class=&#34;k&#34;&gt;\hfill\CROP&lt;/span&gt;@upedge&lt;span class=&#34;k&#34;&gt;\hfill\null\CROP&lt;/span&gt;@urc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\vfill&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\CROP&lt;/span&gt;@ledge&lt;span class=&#34;k&#34;&gt;\hfill\CROP&lt;/span&gt;@redge
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\vfill&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\CROP&lt;/span&gt;@ledge&lt;span class=&#34;k&#34;&gt;\hfill\CROP&lt;/span&gt;@redge
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\vfill&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\CROP&lt;/span&gt;@ledge&lt;span class=&#34;k&#34;&gt;\hfill\CROP&lt;/span&gt;@redge
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\vfill&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\CROP&lt;/span&gt;@ledge&lt;span class=&#34;k&#34;&gt;\hfill\CROP&lt;/span&gt;@redge
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\vfill&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\CROP&lt;/span&gt;@ledge&lt;span class=&#34;k&#34;&gt;\hfill\CROP&lt;/span&gt;@redge
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\vfill&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\CROP&lt;/span&gt;@ledge&lt;span class=&#34;k&#34;&gt;\hfill\CROP&lt;/span&gt;@redge
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\vfill&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\CROP&lt;/span&gt;@llc&lt;span class=&#34;k&#34;&gt;\null\hfill\CROP&lt;/span&gt;@loedge&lt;span class=&#34;k&#34;&gt;\hfill\CROP&lt;/span&gt;@loedge&lt;span class=&#34;k&#34;&gt;\hfill\null\CROP&lt;/span&gt;@lrc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now simply prepare a page which shows a 3x7 grid of tags, using the same rules as before, and our modified &lt;code&gt;crop-3x7.sty&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-latex&#34; data-lang=&#34;latex&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\documentclass&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;article&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% This file demonstrates the use of a customisation to the &amp;#39;crop&amp;#39; package to render additional axes for cutting up small name labels.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\usepackage&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;pdfpages&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Sum of dimensions of the pages. We are displaying 3x7 small tags (60 x 30 mm) to a page, which is where 180x210 comes from.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\usepackage&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;[paperheight=210mm,paperwidth=180mm]&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;geometry&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Include print/output paper size and orientation here, A3 portrait in this example (use &amp;#39;landscape&amp;#39; option for landscape)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\usepackage&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;[axes,cam,a4,pdftex,center]&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;crop-3x7&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\begin&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;document&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Restrict page range, and set arrangement of pages per sheet here.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\includepdf&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;[pages=-,nup=3x7,noautoscale]&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;labels.pdf&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\end&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;document&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Render the document, and see the small dashes on the sides which will show you where to cut (again, click &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/labels-print.pdf&#34; &gt;here&lt;/a&gt; for PDF):&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/labels-print.png&#34;
	width=&#34;4961&#34;
	height=&#34;7016&#34;
	srcset=&#34;https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/labels-print_hu_5a2f406d29d261d9.png 480w, https://mike42.me/blog/2016-01-how-to-arrange-pages-for-printing-and-cutting-in-latex/labels-print_hu_be123000b9ef12dd.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;70&#34;
		data-flex-basis=&#34;169px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap-up
&lt;/h2&gt;&lt;p&gt;Full source for the linked files can be found in my &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/tex-examples&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/tex-examples&lt;/a&gt; repository on GitHub.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to print red/black on an impact receipt printer</title>
        <link>https://mike42.me/blog/2015-12-red-black-impact-receipt-printing</link>
        <pubDate>Sun, 27 Dec 2015 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2015-12-red-black-impact-receipt-printing</guid>
        <description>&lt;p&gt;I recently deployed an Epson TM-U220 impact receipt printer. These printers work by striking a ribbon onto the paper, like a type-writer. One of the up-sides to using these intead of a thermal printer is the ability to install a red/black ribbon in place of the default (black) one:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-12-red-black-impact-receipt-printing/2015-10-colour-receipt-printing-1.jpg&#34;
	width=&#34;2536&#34;
	height=&#34;1084&#34;
	srcset=&#34;https://mike42.me/blog/2015-12-red-black-impact-receipt-printing/2015-10-colour-receipt-printing-1_hu_8873c6874c09893d.jpg 480w, https://mike42.me/blog/2015-12-red-black-impact-receipt-printing/2015-10-colour-receipt-printing-1_hu_78b07a3acf94ddef.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;233&#34;
		data-flex-basis=&#34;561px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-12-red-black-impact-receipt-printing/2015-10-colour-receipt-printing-2.jpg&#34;
	width=&#34;2184&#34;
	height=&#34;1240&#34;
	srcset=&#34;https://mike42.me/blog/2015-12-red-black-impact-receipt-printing/2015-10-colour-receipt-printing-2_hu_acef4e5a4a696b31.jpg 480w, https://mike42.me/blog/2015-12-red-black-impact-receipt-printing/2015-10-colour-receipt-printing-2_hu_a3fa8f4bf1d0962f.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;176&#34;
		data-flex-basis=&#34;422px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I connected up my printer using a USB-parallel cable, so my previous posts (&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows&#34; &gt;Windows&lt;/a&gt;, &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2015-03-getting-a-usb-receipt-printer-working-on-linux&#34; &gt;Linux&lt;/a&gt;) apply for the connector setup.&lt;/p&gt;
&lt;p&gt;Using the &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;escpos-php&lt;/a&gt; driver on GitHub, a line of red text is printed like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * Example of two-color printing, tested on an epson TM-U220 with two-color ribbon installed.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;php://stdout&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;try&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Escpos&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello World!&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setColor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;COLOR_2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Red?!&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setColor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;COLOR_1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Default color again?!&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;finally&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Always close the printer! */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With this result:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-12-red-black-impact-receipt-printing/2015-10-colour-receipt-printing-3.jpg&#34;
	width=&#34;700&#34;
	height=&#34;155&#34;
	srcset=&#34;https://mike42.me/blog/2015-12-red-black-impact-receipt-printing/2015-10-colour-receipt-printing-3_hu_5b02369b5bc9859f.jpg 480w, https://mike42.me/blog/2015-12-red-black-impact-receipt-printing/2015-10-colour-receipt-printing-3_hu_1949e9ea26ff5d4b.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;451&#34;
		data-flex-basis=&#34;1083px&#34;
	
&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to connect a USB receipt printer up on Mac OS X</title>
        <link>https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x</link>
        <pubDate>Thu, 05 Nov 2015 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x</guid>
        <description>&lt;p&gt;This post will show you how to set up a USB receipt printer on Max OS X. These steps were written on  &lt;em&gt;Yosemite&lt;/em&gt;, but should work on 10.6 onwards (ie, also &lt;em&gt;Snow Leopard&lt;/em&gt; through to &lt;em&gt;El Capitan&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;This is another post in a series, which has so far covered direct USB printing on &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows&#34; &gt;Windows&lt;/a&gt; and &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2015-03-getting-a-usb-receipt-printer-working-on-linux&#34; &gt;Linux&lt;/a&gt;. The printer tested here is this Epson TM-T20:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-03-printer-back.jpg&#34;
	width=&#34;3264&#34;
	height=&#34;1928&#34;
	srcset=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-03-printer-back_hu_b781acf3f749364d.jpg 480w, https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-03-printer-back_hu_88880f933c013dcc.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;169&#34;
		data-flex-basis=&#34;406px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-03-printer-top.jpg&#34;
	width=&#34;2460&#34;
	height=&#34;1816&#34;
	srcset=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-03-printer-top_hu_eb82a29bb98b6db0.jpg 480w, https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-03-printer-top_hu_6227b6e59edbc1af.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;135&#34;
		data-flex-basis=&#34;325px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;CUPS is the printing system that&amp;rsquo;s used on Mac, but most users would be more familiar with the system print dialog:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-12.png&#34;
	width=&#34;635&#34;
	height=&#34;546&#34;
	srcset=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-12_hu_3abbfe14020d6c31.png 480w, https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-12_hu_75c2b32078f8985b.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;116&#34;
		data-flex-basis=&#34;279px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;enable-cups-web&#34;&gt;Enable CUPS web
&lt;/h2&gt;&lt;p&gt;In this case, we need to set up the printer via the CUPS web interface. This is accessed via a web browser at this address:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;http://localhost:631
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At first, you will get knocked back:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-0.png&#34;
	width=&#34;806&#34;
	height=&#34;448&#34;
	srcset=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-0_hu_b87eb2a6137ff46e.png 480w, https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-0_hu_bb97f3bd7d05aa77.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;179&#34;
		data-flex-basis=&#34;431px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;To fix this up, open up &lt;strong&gt;Applications → Utilities → Terminal&lt;/strong&gt; and type in:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cupsctl WebInterface=yes
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;add-the-printer&#34;&gt;Add the printer
&lt;/h2&gt;&lt;p&gt;You can then reload the browser and click through to &lt;strong&gt;Administration&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-1.png&#34;
	width=&#34;806&#34;
	height=&#34;448&#34;
	srcset=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-1_hu_fc1911090dcc7ec4.png 480w, https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-1_hu_d07921817687ea23.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;179&#34;
		data-flex-basis=&#34;431px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Click &lt;strong&gt;Add Printer&lt;/strong&gt; and log in:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-2.png&#34;
	width=&#34;1027&#34;
	height=&#34;642&#34;
	srcset=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-2_hu_ec95813011470108.png 480w, https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-2_hu_5781b90577867bda.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;159&#34;
		data-flex-basis=&#34;383px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-3.png&#34;
	width=&#34;1027&#34;
	height=&#34;642&#34;
	srcset=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-3_hu_15d314759de3b416.png 480w, https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-3_hu_29e4020afa230dd.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;159&#34;
		data-flex-basis=&#34;383px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Select the USB printer from the list, and optionally share it:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-4.png&#34;
	width=&#34;1027&#34;
	height=&#34;642&#34;
	srcset=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-4_hu_e80ca5a5105b502.png 480w, https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-4_hu_a573a0caf9884623.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;159&#34;
		data-flex-basis=&#34;383px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-5.png&#34;
	width=&#34;1027&#34;
	height=&#34;642&#34;
	srcset=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-5_hu_8129b6ec49292c14.png 480w, https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-5_hu_1d0565b4c43f8a73.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;159&#34;
		data-flex-basis=&#34;383px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Click &lt;strong&gt;Select Another Make/Manufacturer&lt;/strong&gt;, and select &lt;strong&gt;Raw → Raw Queue&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-6.png&#34;
	width=&#34;1027&#34;
	height=&#34;642&#34;
	srcset=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-6_hu_300d38ebdc8a687f.png 480w, https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-6_hu_b55256c91fb7756b.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;159&#34;
		data-flex-basis=&#34;383px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-7.png&#34;
	width=&#34;1027&#34;
	height=&#34;642&#34;
	srcset=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-7_hu_1896e6e1441aab70.png 480w, https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-7_hu_dfc850520b128443.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;159&#34;
		data-flex-basis=&#34;383px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-8.png&#34;
	width=&#34;1027&#34;
	height=&#34;642&#34;
	srcset=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-8_hu_f7a0ee641c3fa06a.png 480w, https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-8_hu_2da4e0f3b0f83f24.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;159&#34;
		data-flex-basis=&#34;383px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Use the defaults for the other options:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-9.png&#34;
	width=&#34;1027&#34;
	height=&#34;642&#34;
	srcset=&#34;https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-9_hu_f3b52679e957015f.png 480w, https://mike42.me/blog/2015-10-how-to-connect-a-usb-receipt-printer-up-on-mac-os-x/2015-11-mac-usb-epson-9_hu_dd41360292bb86fd.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;159&#34;
		data-flex-basis=&#34;383px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;test-print&#34;&gt;Test print
&lt;/h2&gt;&lt;p&gt;Type some junk into a file called &lt;code&gt;foo.txt&lt;/code&gt; and attempt to print it, using the CUPS printer name:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nano foo.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lpr -o raw -H localhost -P EPSON_TM-T20 foo.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The prints will be delayed for a few moments, as CUPS spools the jobs.&lt;/p&gt;
&lt;h2 id=&#34;disable-cups-web&#34;&gt;Disable CUPS web
&lt;/h2&gt;&lt;p&gt;Once you&amp;rsquo;re done, for security reasons you should reset this option from before, to disable the web interface to CUPS:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cupsctl WebInterface=no
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>How to set up sudo on Debian GNU/Linux</title>
        <link>https://mike42.me/blog/2015-10-how-to-set-up-sudo-on-debian-gnulinux</link>
        <pubDate>Sun, 18 Oct 2015 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2015-10-how-to-set-up-sudo-on-debian-gnulinux</guid>
        <description>&lt;p&gt;If you just installed Debian, you might notice that one Linux staple, &lt;code&gt;sudo&lt;/code&gt; is not installed by default. Here is the quick way to add it, and set yourself up as an administrative user.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Install sudo&lt;/strong&gt;, using the &lt;code&gt;su&lt;/code&gt; command to elevate privileges.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;bob$ su
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Password: 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root# apt-get install sudo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;2. Make yourself an administrator.&lt;/strong&gt; The default &lt;code&gt;/etc/sudoers&lt;/code&gt; file contains this line:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# Allow members of group sudo to execute any command
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;%sudo	ALL=(ALL:ALL) ALL
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So simply add your account (&amp;lsquo;bob&amp;rsquo; in this example) to the &lt;code&gt;sudo&lt;/code&gt; group:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root# usermod -a -G sudo bob
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;3. Log out and back in again&lt;/strong&gt;, in order to apply changes to your group membership.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;bob$ groups
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;bob cdrom floppy sudo audio dip video plugdev netdev lpadmin scanner bluetooth
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;bob$ sudo echo test
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[sudo] password for bob: 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;test
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>Fix merge conflicts in git with Meld</title>
        <link>https://mike42.me/blog/2015-09-fix-merge-conflicts-in-git-with-meld</link>
        <pubDate>Wed, 16 Sep 2015 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2015-09-fix-merge-conflicts-in-git-with-meld</guid>
        <description>&lt;p&gt;When you&amp;rsquo;re writing code collaboratively, there&amp;rsquo;s plenty of situations when you need to combine two sets of changes.&lt;/p&gt;
&lt;p&gt;This could happen, for example, if Bob and yourself both fix different bugs by making edits to the same file.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-09-fix-merge-conflicts-in-git-with-meld/2015-10-merge-diagram.png&#34;
	width=&#34;283&#34;
	height=&#34;155&#34;
	srcset=&#34;https://mike42.me/blog/2015-09-fix-merge-conflicts-in-git-with-meld/2015-10-merge-diagram_hu_bc7582f6e11854b1.png 480w, https://mike42.me/blog/2015-09-fix-merge-conflicts-in-git-with-meld/2015-10-merge-diagram_hu_2cb1d550d2edc98.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;182&#34;
		data-flex-basis=&#34;438px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This post assumes that your source code is tracked in git.&lt;/p&gt;
&lt;p&gt;First up, install meld. The &lt;a class=&#34;link&#34; href=&#34;http://meldmerge.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Meld homepage&lt;/a&gt; has instructions for other platforms, but on Debian/Ubuntu, it&amp;rsquo;s just:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install meld
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;usage-with-git&#34;&gt;Usage with git
&lt;/h2&gt;&lt;p&gt;Now tell git to use it as a tool:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;global&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;merge&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;tool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;meld&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once you have a merge conflict, you can then fire up Meld like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mergetool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For each file, you will get a 3-way diff. Click the arrows on the sides to move the code you want into the middle:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-09-fix-merge-conflicts-in-git-with-meld/2015-10-meld.png&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2015-09-fix-merge-conflicts-in-git-with-meld/2015-10-meld_hu_971f287d5abf60c1.png 480w, https://mike42.me/blog/2015-09-fix-merge-conflicts-in-git-with-meld/2015-10-meld_hu_4f79bff4f58d7872.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;ve saved the file and closed Meld, you will be prompted on the command-line. You just tell it whether you&amp;rsquo;ve successfully merged the file, until it stops giving you new files to merge.&lt;/p&gt;
&lt;p&gt;After this, commit the changes:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git commit
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Done!&lt;/p&gt;
&lt;h2 id=&#34;standalone-usage&#34;&gt;Standalone usage
&lt;/h2&gt;&lt;p&gt;If you don&amp;rsquo;t use git, you can simply call Meld from the command-line as well. This shows you differences between files in a similar window, and lets you move blocks of code around as well:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;meld foo.c bar.c
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>Continuous testing in PHP with Eclipse</title>
        <link>https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse</link>
        <pubDate>Thu, 13 Aug 2015 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse</guid>
        <description>&lt;p&gt;If you already write test cases over your code, then continuous testing is a simple idea: Get fast feedback on your code by running your project&amp;rsquo;s unit tests very frequently. From PHP, the de facto standard testing tool is PHPUnit, so running tests usually involves typing &lt;code&gt;phpunit&lt;/code&gt; into a terminal.&lt;/p&gt;
&lt;p&gt;This post will show you how to set up a project with the Eclipse MakeGood plugin, which is a continuous test runner for the Eclipse IDE. When it is enabled, the plugin runs a set of tests every time you save a file.&lt;/p&gt;
&lt;p&gt;This is best used on projects which are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Small&lt;/strong&gt; — so your tests run in a reasonable timeframe.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Complex&lt;/strong&gt; — reasonably high risk of introducing defects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Well-tested&lt;/strong&gt; — so your unit tests are reasonably likely to identify defects.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;set-up-your-machine&#34;&gt;Set up your machine
&lt;/h2&gt;&lt;p&gt;Your machine needs Eclipse PDT, MakeGood and composer.&lt;/p&gt;
&lt;h3 id=&#34;eclipse-pdt&#34;&gt;Eclipse PDT
&lt;/h3&gt;&lt;p&gt;If you&amp;rsquo;ve found this post via Google, then you probably already run Eclipse and PHP. If not, fetch the &amp;ldquo;Eclipse for PHP developers&amp;rdquo; distribution from &lt;a class=&#34;link&#34; href=&#34;https://eclipse.org/downloads/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You need to pick up the XDebug extension to really make use of this setup. On Debian-based distributions, this is achieved via:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;sudo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;apt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;get&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;install&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;php5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;xdebug&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you don&amp;rsquo;t use Eclipse yet, then check whether languages or tools you&amp;rsquo;ve used before have plugins in the &lt;a class=&#34;link&#34; href=&#34;https://marketplace.eclipse.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Eclipse Marketplace&lt;/a&gt;. There&amp;rsquo;s a good chance that Eclipse will do the whole lot.&lt;/p&gt;
&lt;h3 id=&#34;makegood&#34;&gt;MakeGood
&lt;/h3&gt;&lt;p&gt;MakeGood is simply an Eclipse plugin, so you can fetch it from the Eclipse Marketplace.&lt;/p&gt;
&lt;p&gt;Navigate to &lt;strong&gt;Help → Eclipse Marketplace&lt;/strong&gt; and search for &amp;ldquo;makegood&amp;rdquo;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-eclipse-makegood-01.png&#34;
	width=&#34;650&#34;
	height=&#34;485&#34;
	srcset=&#34;https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-eclipse-makegood-01_hu_d35ba99821923b50.png 480w, https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-eclipse-makegood-01_hu_9be3b44ec9aa81f9.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;134&#34;
		data-flex-basis=&#34;321px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Wait for the info to be fetched:&lt;/p&gt;
&lt;p&gt;Check all the boxes, and then click &lt;strong&gt;Confirm&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-eclipse-makegood-03.png&#34;
	width=&#34;764&#34;
	height=&#34;741&#34;
	srcset=&#34;https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-eclipse-makegood-03_hu_e5dea47393eb418b.png 480w, https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-eclipse-makegood-03_hu_c6d5faba329aa46f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;103&#34;
		data-flex-basis=&#34;247px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Accept the terms, and wait for the install:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-eclipse-makegood-02.png&#34;
	width=&#34;613&#34;
	height=&#34;316&#34;
	srcset=&#34;https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-eclipse-makegood-02_hu_752b286116279ca1.png 480w, https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-eclipse-makegood-02_hu_cc018ec63049af25.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;193&#34;
		data-flex-basis=&#34;465px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;At one point, you will be prompted to accept a developer&amp;rsquo;s certificate, which you need to do before continuing:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-eclipse-makegood-04.png&#34;
	width=&#34;761&#34;
	height=&#34;702&#34;
	srcset=&#34;https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-eclipse-makegood-04_hu_e4aaba091548c405.png 480w, https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-eclipse-makegood-04_hu_5a1cc7069bd16c13.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;108&#34;
		data-flex-basis=&#34;260px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This feature will not work unless you have a PHP binary set up. You need to configure this under **Window &amp;rarr; Preferences &amp;rarr; PHP &amp;rarr; PHP executables.**:
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-07-eclipse-add-php-executable.png&#34;
	width=&#34;741&#34;
	height=&#34;491&#34;
	srcset=&#34;https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-07-eclipse-add-php-executable_hu_a5648cd4216c39ef.png 480w, https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-07-eclipse-add-php-executable_hu_3fd27458149f12e6.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;150&#34;
		data-flex-basis=&#34;362px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This is system dependent: Windows users will find a file somewhere called &lt;code&gt;php-cli.exe&lt;/code&gt;, while Linux users might find it at &lt;code&gt;/usr/bin/php&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After this, MakeGood is installed. It is configured per-project, so we&amp;rsquo;ll get to that after the next section.&lt;/p&gt;
&lt;h3 id=&#34;composer&#34;&gt;Composer
&lt;/h3&gt;&lt;p&gt;Composer is a dependency manager which is widely used in the PHP world.&lt;/p&gt;
&lt;p&gt;You can get it from [https://getcomposer.org/download/](https://getcomposer.org/download/)
&lt;p&gt;Rather than use the install process which is suggested there, you can simply download the phar, make it executable, and place it somewhere like &lt;code&gt;/usr/bin&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wget https://getcomposer.org/composer.phar
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chmod +x composer.phar
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo mv composer.phar /usr/bin/composer
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;composer --version
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By using composer to load PHPUnit, MakeGood becomes much easier to configure.&lt;/p&gt;
&lt;h2 id=&#34;project-setup&#34;&gt;Project setup
&lt;/h2&gt;&lt;p&gt;To start, make a new PHP project by clicking &lt;strong&gt;File → New → PHP Project&lt;/strong&gt;. Name it something like &amp;ldquo;Example&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;We are using composer here because it provides an easy way to make sure MakeGood can see the PHPUnit code. So let&amp;rsquo;s set a few things up:&lt;/p&gt;
&lt;p&gt;First, add a &lt;code&gt;composer.json&lt;/code&gt; file which adds a recent version of PHPUnit as a &lt;code&gt;require-dev&lt;/code&gt; dependency. Right-click &lt;strong&gt;Example&lt;/strong&gt; project, and navigate to &lt;strong&gt;New → File&lt;/strong&gt;, naming it &lt;code&gt;composer.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;require-dev&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;phpunit/phpunit&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;4.5.*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that with the way that MakeGood constructs its command-line, newer versions of PHPUnit do not appear to work correctly at the time of writing.&lt;/p&gt;
&lt;p&gt;Next up, install the new dependency with the help of Composer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ composer install
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loading composer repositories with package information
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Installing dependencies (including require-dev)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing sebastian/version (1.0.6)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing sebastian/global-state (1.0.0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing sebastian/recursion-context (1.0.1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing sebastian/exporter (1.2.1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing sebastian/environment (1.3.2)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing sebastian/diff (1.3.0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing sebastian/comparator (1.2.0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing symfony/yaml (v2.7.3)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing doctrine/instantiator (1.0.5)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing phpdocumentor/reflection-docblock (2.0.4)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing phpspec/prophecy (v1.4.1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing phpunit/php-text-template (1.2.1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing phpunit/phpunit-mock-objects (2.3.6)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing phpunit/php-timer (1.0.7)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing phpunit/php-token-stream (1.4.3)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing phpunit/php-file-iterator (1.3.4)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing phpunit/php-code-coverage (2.2.2)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Installing phpunit/phpunit (4.5.1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sebastian/global-state suggests installing ext-uopz (*)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;phpdocumentor/reflection-docblock suggests installing dflydev/markdown (~1.0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;phpdocumentor/reflection-docblock suggests installing erusev/parsedown (~1.0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;phpunit/phpunit suggests installing phpunit/php-invoker (~1.1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Writing lock file
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Generating autoload files
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Set up an &lt;code&gt;Example.php&lt;/code&gt; class with a bit of code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * Example of some code that could do with test cases
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Example&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;	 * Faulty palindrome checker. A palindrome is a word which is the same when read orward and backward.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;	 * 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;	 * @param string $str
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;	 * @return boolean True if $str is a palindrome, false if it is not.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;	 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;isPalindrone&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nv&#34;&gt;$halfLen&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;strlen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$halfLen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;c1&#34;&gt;// Compare characters from the front and back of the string, and move toward the middle.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;			&lt;span class=&#34;nv&#34;&gt;$c1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;substr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;nv&#34;&gt;$c2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;substr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$halfLen&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$c1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$c2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;				&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;		
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Set up a &lt;code&gt;test/unit&lt;/code&gt; folder and create a &lt;code&gt;ExampleTest&lt;/code&gt; class with a useful test case in it, like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;ExampleTest&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;extends&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;PHPUnit_Framework_TestCase&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;testIsPalindrome&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Example&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;assertTrue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;isPalindrone&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;assertTrue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;isPalindrone&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;assertTrue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;isPalindrone&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ABBA&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;assertFalse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;isPalindrone&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The unit tests go in their own folder, in case you decide to add more extensive (slower) tests later. MakeGood should only be configured to run &lt;em&gt;fast tests&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;Now add a &lt;code&gt;test/bootstrap.php&lt;/code&gt; for test cases to load classes (NB: At scale, you would have composer autoload your classes, and use that as your PHPUnit class loader).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require_once&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;vendor/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require_once&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;Example.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Optionally, also add a &lt;code&gt;phpunit.xml&lt;/code&gt; file in your project root to configure PHPUnit with, so that you can run it on the command-line:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;phpunit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;nx&#34;&gt;xmlns&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;xsi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;http://www.w3.org/2001/XMLSchema-instance&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;nx&#34;&gt;xsi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;noNamespaceSchemaLocation&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;http://schema.phpunit.de/4.5/phpunit.xsd&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;nx&#34;&gt;bootstrap&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;test/bootstrap.php&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;phpunit&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If all goes to plan, your project should look something like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- Continuous testing example
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  |- (.. code ..)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  |- Example.php
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  |- test/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  |  |- (.. other types of tests ..) 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  |  |- unit/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  |  | |- ExampleTest.php
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  |  |- bootstrap.php
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  |- vendor
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  |  |- (.. dependencies ..)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  |  |- autoload.php
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  |- composer.json
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  |- phpunit.xml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And more to the point, you should be able to use PHPUnit on the command-line to run the test case. It will look something like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Example$ php vendor/bin/phpunit test/unit/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PHPUnit 4.7.7 by Sebastian Bergmann and contributors.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Time: 71 ms, Memory: 4.50Mb
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;OK (1 test, 4 assertions)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;configure-makegood&#34;&gt;Configure MakeGood
&lt;/h2&gt;&lt;p&gt;Now that the project is coming along nicely, it&amp;rsquo;s time to configure MakeGood to run the test automatically from within Eclipse.&lt;/p&gt;
&lt;p&gt;Go to &lt;strong&gt;Project → Properties → MakeGood&lt;/strong&gt;, and add the path to your unit tests, along with a link to the &lt;code&gt;bootstrap.php&lt;/code&gt;. This bootstrap file will let MakeGood load the classes to test, along with PHPUnit itself.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-makegood-demo1.png&#34;
	width=&#34;665&#34;
	height=&#34;587&#34;
	srcset=&#34;https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-makegood-demo1_hu_461ccba6906b3b0c.png 480w, https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-makegood-demo1_hu_36c989971a835ebf.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;113&#34;
		data-flex-basis=&#34;271px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Now fire up the MakeGood view. If it doesn&amp;rsquo;t come up automatically, then open it via &lt;strong&gt;Window → Show View → Other&lt;/strong&gt;. Clicking the &amp;ldquo;play&amp;rdquo; button should kick off all available tests, adn if your project structure is correct, then everything will work at this point:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-makegood-demo2.png&#34;
	width=&#34;602&#34;
	height=&#34;403&#34;
	srcset=&#34;https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-makegood-demo2_hu_49e78956fa904670.png 480w, https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-makegood-demo2_hu_e74fe9453533bbaf.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;149&#34;
		data-flex-basis=&#34;358px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Once you save a file, a small box will appear in the bottom-right to indicate whether the tests worked.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-makegood-demo3.png&#34;
	width=&#34;1223&#34;
	height=&#34;738&#34;
	srcset=&#34;https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-makegood-demo3_hu_17f16d0264501748.png 480w, https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-makegood-demo3_hu_a4649037f1ef413.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;165&#34;
		data-flex-basis=&#34;397px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;As you introduce changes and save them, MakeGood will flag whether the tests are passing by changing the colour of the icon.&lt;/p&gt;
&lt;p&gt;In this case, it is green. From the small delay that is caused when running the tests, you can see why it&amp;rsquo;s important to keep unit tests fast if you use this tool.&lt;/p&gt;
&lt;h2 id=&#34;a-test-driven-bugfix-cycle&#34;&gt;A test-driven bugfix cycle
&lt;/h2&gt;&lt;p&gt;Of course, &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Linus%27s_Law&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Linus&amp;rsquo; Law&lt;/a&gt; suggests that any code will probably have more bugs. So, say somebody reports that the palindrome &amp;ldquo;abcdedcba&amp;rdquo; is causing incorrect results. In test-driven development, you would expose this as a test case over the &lt;code&gt;isPalindrome()&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;testIsPalindromeOddLength&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Example&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;assertTrue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;isPalindrone&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;abcdedcba&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;assertFalse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;isPalindrone&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;abc&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As soon as this is submitted, things start to turn red in MakeGood. In response to the broken test, you can then tweak the code.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-makegood-demo4.png&#34;
	width=&#34;1223&#34;
	height=&#34;738&#34;
	srcset=&#34;https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-makegood-demo4_hu_e5e9e098694ed142.png 480w, https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-makegood-demo4_hu_9bbb6efea31428a0.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;165&#34;
		data-flex-basis=&#34;397px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;You would then do the smallest amount of programming needed to pass all the tests. A palindrome checker which does not contain intentional bugs is as simple as this one-liner:
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;isPalindrone&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$str&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;strrev&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This change causes MakeGood to report that the unit tests are all passing.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-makegood-demo5.png&#34;
	width=&#34;1223&#34;
	height=&#34;738&#34;
	srcset=&#34;https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-makegood-demo5_hu_57d66e5d5124ccc.png 480w, https://mike42.me/blog/2015-08-continuous-testing-in-php-with-eclipse/2015-06-makegood-demo5_hu_399c8c723b7355e0.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;165&#34;
		data-flex-basis=&#34;397px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;summary&#34;&gt;Summary
&lt;/h2&gt;&lt;p&gt;A continuous test runner adds faster feedback for tedious but well-tested code. If you have to write anything in PHP which does some real computer work, then I suggest setting up MakeGood so that you can make changes to tricky code, and have a good idea of whether it&amp;rsquo;s producing sane outputs.&lt;/p&gt;
&lt;p&gt;As this post has touched on before, slow tests should not run each time you save the code. This is why we worked in a &lt;em&gt;Unit test&lt;/em&gt; folder. Slower integration or functional tests can still be run via the command-line in this model. An example of a project which uses this setup is &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/escpos-php&lt;/a&gt;, which is a heavily test-driven PHP driver for thermal line printers.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>It&#39;s time to migrate away from Outlook Express</title>
        <link>https://mike42.me/blog/2015-06-its-time-to-migrate-away-from-outlook-express</link>
        <pubDate>Thu, 18 Jun 2015 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2015-06-its-time-to-migrate-away-from-outlook-express</guid>
        <description>&lt;p&gt;Outlook Express is obsolete, so &lt;em&gt;you need to migrate&lt;/em&gt; if you&amp;rsquo;re still using it. This post is a quick guide to saving your local data so that you can jump ship.&lt;/p&gt;
&lt;p&gt;If you are keen on desktop-based email, then there are only two real contenders for a replacement mail client:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mozilla Thunderbird (suggested).&lt;/li&gt;
&lt;li&gt;Windows Mail.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;so-where-is-all-my-data&#34;&gt;So where is all my data?
&lt;/h2&gt;&lt;p&gt;The script below is a Windows &lt;code&gt;bat&lt;/code&gt; script for backing up an Outlook Express setup. Just fill in the Identity variable and run it from anywhere to produce a folder containing the Outlook saved emails and contacts.&lt;/p&gt;
&lt;p&gt;You can find your identity string as a folder name in your profile path, under &lt;code&gt;Local Settings\Application Data\Identities\&lt;/code&gt;. The profile path for a user called &lt;code&gt;bob&lt;/code&gt; would usually be in a folder like &lt;code&gt;C:\Documents and Settings\bob&lt;/code&gt; or &lt;code&gt;C:\Users\bob&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;These files can be read by both of the mentioned replacements, so a good transition might be:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Make a backup.&lt;/li&gt;
&lt;li&gt;Install an alternative &amp;amp; set it up.&lt;/li&gt;
&lt;li&gt;Try to import as much as you can.&lt;/li&gt;
&lt;li&gt;Once you&amp;rsquo;re happy, uninstall Outlook Express, or at least delete the shortcuts to it.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-batch&#34; data-lang=&#34;batch&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; off
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;ECHO&lt;/span&gt; -------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;SET&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;BACKUPDIR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;%username%&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; - Outlook Backup&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;SET&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;IDENTITY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&lt;/span&gt;{AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;ECHO&lt;/span&gt; Backing up outlook files to: &lt;span class=&#34;nv&#34;&gt;%backupdir%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;ECHO&lt;/span&gt; --------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;ECHO&lt;/span&gt; - Clearing backup location... (1 of 3) 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;DEL&lt;/span&gt; /F /S /Q &lt;span class=&#34;nv&#34;&gt;%backupdir%&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt; NUL &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;MKDIR&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;%backupdir%&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt; NUL
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;ECHO&lt;/span&gt; - - Done
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;ECHO&lt;/span&gt; - Copying emails... (2 of 3) 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;MKDIR&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;%backupdir%&lt;/span&gt;\Emails &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt; NUL
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;XCOPY /E /H /C /R /Y &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;%userprofile%&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;\Local Settings\Application Data\Identities\&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;%IDENTITY%&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;\Microsoft\Outlook Express&amp;#34;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;%backupdir%&lt;/span&gt;\Emails &lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt; NUL
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;ECHO&lt;/span&gt; - - Done
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;ECHO&lt;/span&gt; - Copying address book... (3 of 3)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;MKDIR&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;%backupdir%&lt;/span&gt;\AddressBook &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt; NUL
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;XCOPY /E /H /C /R /Y &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;%appdata%&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;\Microsoft\Address Book&amp;#34;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;%backupdir%&lt;/span&gt;\AddressBook &lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt; NUL
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;ECHO&lt;/span&gt; - - Done
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;ECHO&lt;/span&gt; - Completed 3 of 3 tasks.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;ECHO&lt;/span&gt; -------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;ECHO&lt;/span&gt; The backup is complete.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;ECHO&lt;/span&gt; Please copy &lt;span class=&#34;nv&#34;&gt;%BACKUPDIR%&lt;/span&gt; to external storage.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;ECHO&lt;/span&gt; --------------------------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;PAUSE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>How to create an animated GIF from a series of images</title>
        <link>https://mike42.me/blog/2015-06-how-to-create-an-animated-gif-from-a-series-of-images</link>
        <pubDate>Thu, 11 Jun 2015 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2015-06-how-to-create-an-animated-gif-from-a-series-of-images</guid>
        <description>&lt;p&gt;Sometimes, you end up with &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2014-01-31_scripted_screen_captures&#34; &gt;a folder full of images&lt;/a&gt;, which you want to animate. With the open source ImageMagick tool, this is easy on the command line:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;animate *.png
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will show you all of the PNG files in the folder in quick succession, like a flip book.&lt;/p&gt;
&lt;p&gt;ImageMagick works on just about any OS. For Linux users, it should be in your package manager.&lt;/p&gt;
&lt;p&gt;On Debian you would install it via:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install imagemagick
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or on Red Hat it is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo yum install ImageMagick
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But this blog post is about animated GIFs, so lets make one of those. This is a compact way to combine images (&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi&#34; &gt;here&lt;/a&gt; and &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2015-03-how-to-run-tetris-on-your-raspberry-pi&#34; &gt;here&lt;/a&gt; for examples in context), gives you a re-usable at-a-glance illustration of something that changes over time.&lt;/p&gt;
&lt;p&gt;Example from an older post:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-06-how-to-create-an-animated-gif-from-a-series-of-images/2015-04-tetris.gif&#34;
	width=&#34;400&#34;
	height=&#34;236&#34;
	
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;169&#34;
		data-flex-basis=&#34;406px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The steps to make a good conversion command are below.&lt;/p&gt;
&lt;p&gt;Check that alphabetically, your images are in order. If not, rename them:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;echo *
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Convert them to a GIF, and find the &lt;strong&gt;delay&lt;/strong&gt; that suits you (hundredths of a second between frames). You will want to repeat this a few times to find the delay value which works for you:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;convert -delay 80 *.png animated.gif
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Choose an output size (width x height):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;convert -resize 415x -delay 80 *.png animated.gif
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Compress with &lt;code&gt;-Layers Optimize&lt;/code&gt; for a smaller file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;convert -resize 415x -delay 80 *.png -layers Optimize animated.gif
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;notes&#34;&gt;Notes
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Generated thumbnails usually take the first frame only, which is why we ask Imagemagick to resize it (Wordpress users: Choose &amp;ldquo;Full Size&amp;rdquo;).&lt;/li&gt;
&lt;li&gt;To pause at the start of the loop for a moment, just copy the first image a few times.&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>Raspberry Pi KA Lite wireless deployment</title>
        <link>https://mike42.me/blog/2015-06-raspberry-pi-ka-lite-wireless-deployment</link>
        <pubDate>Thu, 11 Jun 2015 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2015-06-raspberry-pi-ka-lite-wireless-deployment</guid>
        <description>&lt;p&gt;Previous post in this series: &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi&#34; &gt;How to install KA Lite on the Raspberry Pi&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you got to the end of the previous post, you would have a working install of the open source KA Lite system on the Raspberry Pi.&lt;/p&gt;
&lt;p&gt;This post will show you how to deploy this KA Lite setup without relying on any existing network infrastructure:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-06-raspberry-pi-ka-lite-wireless-deployment/dia.png&#34;
	width=&#34;269&#34;
	height=&#34;207&#34;
	srcset=&#34;https://mike42.me/blog/2015-06-raspberry-pi-ka-lite-wireless-deployment/dia_hu_54cf50e14dc55322.png 480w, https://mike42.me/blog/2015-06-raspberry-pi-ka-lite-wireless-deployment/dia_hu_5556f6c25463ae59.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;129&#34;
		data-flex-basis=&#34;311px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;To share the setup without an existing network, we will configure the wireless adapter to provide its own network for computers to connect to. If you have an existing wireless network, you can skip this post.&lt;/p&gt;
&lt;h2 id=&#34;before-you-begin&#34;&gt;Before you begin
&lt;/h2&gt;&lt;p&gt;This post is intended for the widely-used &amp;ldquo;WiPi&amp;rdquo; USB WiFi adapter, so you&amp;rsquo;ll need one of those.&lt;/p&gt;
&lt;p&gt;I used the same Tenda USB WiFi adapter as &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2013-12-21_missile_launcher_on_raspberry_pi&#34; &gt;previous setups&lt;/a&gt;, which has a Ralink chip from the same series:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-06-raspberry-pi-ka-lite-wireless-deployment/2013-12-wifi.jpg&#34;
	width=&#34;450&#34;
	height=&#34;255&#34;
	srcset=&#34;https://mike42.me/blog/2015-06-raspberry-pi-ka-lite-wireless-deployment/2013-12-wifi_hu_7af2c82beaa4912d.jpg 480w, https://mike42.me/blog/2015-06-raspberry-pi-ka-lite-wireless-deployment/2013-12-wifi_hu_9894692bbf8a5bb6.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;176&#34;
		data-flex-basis=&#34;423px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;set-it-up&#34;&gt;Set it up
&lt;/h2&gt;&lt;p&gt;&lt;em&gt;See the &lt;a class=&#34;link&#34; href=&#34;https://learningequality.org/docs/0.13/en/installguide/install_rasp_pi.html#raspberry-pi-wi-fi&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;official guide&lt;/a&gt; for these steps in compact form. These steps are the same, but expanded with extra output from my install.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Clone the &lt;a class=&#34;link&#34; href=&#34;https://github.com/learningequality/ka-lite-pi-scripts.git&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;raspberry pi scripts repo&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ git clone https://github.com/learningequality/ka-lite-pi-scripts.git
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Cloning into &amp;#39;ka-lite-pi-scripts&amp;#39;...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;remote: Counting objects: 66, done.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;remote: Total 66 (delta 0), reused 0 (delta 0), pack-reused 66
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Unpacking objects: 100% (66/66), done.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Open it up and run &lt;code&gt;./configure.sh&lt;/code&gt; as the root user. This requires Internet access, and will install and configure a few packages:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cd&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ka&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lite&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;scripts&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ls&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;README&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;md&lt;/span&gt;     &lt;span class=&#34;n&#34;&gt;configure_network_interfaces&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;py&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;use_wipi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;conf&lt;/span&gt;          &lt;span class=&#34;n&#34;&gt;redirect_port80_to_port8008&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;py&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;configure&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sh&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;use_edimax&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sudo&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;./&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;configure&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrordirector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Release&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gpg&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;490&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;B&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Hit&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspberrypi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;collabora&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;com&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Release&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gpg&lt;/span&gt;                        
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Hit&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;archive&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspberrypi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Release&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gpg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrordirector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Release&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;14.4&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Hit&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspberrypi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;collabora&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;com&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Release&lt;/span&gt;                      
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Hit&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;archive&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspberrypi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Release&lt;/span&gt;                        
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Hit&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspberrypi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;collabora&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;com&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rpi&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Packages&lt;/span&gt;           
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;archive&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspberrypi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Packages&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;129&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;       
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrordirector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Packages&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6903&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Ign&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspberrypi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;collabora&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;com&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rpi&lt;/span&gt; &lt;span class=&#34;ne&#34;&gt;Translation&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;en&lt;/span&gt;                 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Ign&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;archive&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspberrypi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;ne&#34;&gt;Translation&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;en&lt;/span&gt;                
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrordirector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;contrib&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Packages&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;23.6&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrordirector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;non&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;free&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Packages&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;49.3&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrordirector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rpi&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Packages&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;592&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;B&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;     
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Ign&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrordirector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;contrib&lt;/span&gt; &lt;span class=&#34;ne&#34;&gt;Translation&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;en&lt;/span&gt;           
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Ign&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrordirector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;ne&#34;&gt;Translation&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;en&lt;/span&gt;              
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Ign&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrordirector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;non&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;free&lt;/span&gt; &lt;span class=&#34;ne&#34;&gt;Translation&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;en&lt;/span&gt;          
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Ign&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrordirector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rpi&lt;/span&gt; &lt;span class=&#34;ne&#34;&gt;Translation&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;en&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Fetched&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;6992&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;35&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;198&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;             
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Reading&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;lists&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Reading&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;lists&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Building&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dependency&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;tree&lt;/span&gt;       
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Reading&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;information&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;The&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;following&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;packages&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;will&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;be&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;upgraded&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;cups&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bsd&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cups&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;client&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cups&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;common&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fuse&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libcups2&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libcupsimage2&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libfuse2&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;raspi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;upgraded&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;newly&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;installed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;remove&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;upgraded&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Need&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;get&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1708&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;archives&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;After&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;operation&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;306&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;disk&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;space&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;will&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;be&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;freed&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;archive&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspberrypi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;debian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;raspi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;all&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;20150131&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;13.2&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrordirector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libcupsimage2&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;1.5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u6&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;132&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrordirector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cups&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;common&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;all&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;1.5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u6&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;904&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrordirector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cups&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bsd&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;1.5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u6&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;44.2&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrordirector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cups&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;client&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;1.5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u6&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;174&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrordirector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libcups2&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;1.5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u6&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;238&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrordirector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fuse&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;2.9&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u2&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;70.8&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrordirector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libfuse2&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;2.9&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u2&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;132&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Fetched&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1708&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;447&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Preconfiguring&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;packages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Reading&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;database&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;83674&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;files&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;directories&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;currently&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;installed&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Preparing&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;replace&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libcupsimage2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;1.5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u5&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;using&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.../&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;libcupsimage2_1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;5.3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u6_armhf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Unpacking&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;replacement&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libcupsimage2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Preparing&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;replace&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cups&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;common&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;1.5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u5&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;using&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.../&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cups&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;common_1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;5.3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u6_all&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Unpacking&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;replacement&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cups&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;common&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Preparing&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;replace&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cups&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bsd&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;1.5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u5&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;using&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.../&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cups&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bsd_1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;5.3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u6_armhf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;locale&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Cannot&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;set&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LC_ALL&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;locale&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;No&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;such&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Unpacking&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;replacement&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cups&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bsd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Preparing&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;replace&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cups&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;client&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;1.5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u5&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;using&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.../&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cups&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;client_1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;5.3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u6_armhf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Unpacking&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;replacement&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cups&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;client&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Preparing&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;replace&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libcups2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;1.5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u5&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;using&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.../&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;libcups2_1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;5.3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u6_armhf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Unpacking&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;replacement&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libcups2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Preparing&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;replace&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fuse&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;2.9&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u1&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;using&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.../&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fuse_2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;9.0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u2_armhf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Unpacking&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;replacement&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fuse&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Preparing&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;replace&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libfuse2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;2.9&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u1&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;using&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.../&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;libfuse2_2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;9.0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u2_armhf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Unpacking&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;replacement&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libfuse2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Preparing&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;replace&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;raspi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;20150131&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;using&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.../&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config_20150131&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_all&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Unpacking&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;replacement&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;raspi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Processing&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;triggers&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;man&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;db&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Processing&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;triggers&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;initramfs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tools&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Setting&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;up&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libcups2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;1.5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Setting&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;up&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libcupsimage2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;1.5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Setting&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;up&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cups&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;common&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;1.5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Setting&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;up&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cups&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;client&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;1.5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Setting&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;up&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cups&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bsd&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;1.5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Setting&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;up&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libfuse2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;2.9&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Setting&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;up&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fuse&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;2.9&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;udev&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;active&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;skipping&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;device&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;node&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;creation&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;update&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;initramfs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;deferring&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;update&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;trigger&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;activated&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Setting&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;up&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;raspi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;20150131&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;update&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;d&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;warning&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;runlevel&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arguments&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;match&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;raspi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Default&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Start&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;values&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;S&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;update&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;d&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;warning&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;stop&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;runlevel&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arguments&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;match&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;raspi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Default&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Stop&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;values&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;none&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Processing&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;triggers&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;initramfs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tools&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Reading&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;lists&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Building&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dependency&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;tree&lt;/span&gt;       
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Reading&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;information&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;The&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;following&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;extra&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;packages&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;will&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;be&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;installed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;dnsmasq&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libnetfilter&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conntrack3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;The&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;following&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;NEW&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;packages&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;will&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;be&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;installed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;dnsmasq&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dnsmasq&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hostapd&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libnetfilter&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conntrack3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;upgraded&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;newly&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;installed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;remove&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;upgraded&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Need&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;get&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;822&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;archives&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;After&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;operation&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1653&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;additional&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;disk&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;space&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;will&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;be&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;used&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrordirector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libnetfilter&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conntrack3&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;32.2&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrordirector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dnsmasq&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;2.62&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u3&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;356&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrordirector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dnsmasq&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;all&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;2.62&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u3&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;16.3&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrordirector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raspbian&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wheezy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hostapd&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u2&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;418&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Fetched&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;822&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;168&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kB&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Selecting&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;previously&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;unselected&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libnetfilter&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conntrack3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Reading&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;database&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;83674&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;files&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;directories&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;currently&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;installed&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Unpacking&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libnetfilter&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conntrack3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.../&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;libnetfilter&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conntrack3_1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;0.1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_armhf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Selecting&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;previously&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;unselected&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dnsmasq&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Unpacking&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dnsmasq&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.../&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dnsmasq&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base_2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;62&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u3_armhf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Selecting&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;previously&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;unselected&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dnsmasq&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Unpacking&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dnsmasq&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.../&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dnsmasq_2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;62&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u3_all&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Selecting&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;previously&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;unselected&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hostapd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Unpacking&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hostapd&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.../&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hostapd_1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u2_armhf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Processing&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;triggers&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;man&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;db&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Setting&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;up&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libnetfilter&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conntrack3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;armhf&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Setting&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;up&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dnsmasq&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;base&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;2.62&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Setting&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;up&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dnsmasq&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;2.62&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ok&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Starting&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;DNS&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;forwarder&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;DHCP&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dnsmasq&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Setting&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;up&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hostapd&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;1.0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deb7u2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ok&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Starting&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;advanced&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;IEEE&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;802.11&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;management&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hostapd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ok&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Starting&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;DNS&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;forwarder&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;DHCP&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dnsmasq&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;....&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;already&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;running&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;update&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;d&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;using&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dependency&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;based&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;boot&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sequencing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;update&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;d&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;using&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dependency&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;based&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;boot&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sequencing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, run run the &lt;code&gt;./use_wipi.sh&lt;/code&gt; script:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ./use_wipi.sh 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[ ok ] Stopping advanced IEEE 802.11 management: hostapd.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[ ok ] Starting advanced IEEE 802.11 management: hostapd.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And then the &lt;code&gt;./configure_network_interfaces.py&lt;/code&gt; script as root:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo python ./configure_network_interfaces.py
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After this ran, the &lt;code&gt;/etc/network/interfaces&lt;/code&gt; file looked like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo nano /etc/network/interfaces
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;auto lo
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;iface lo inet loopback
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;auto eth0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#allow-hotplug eth0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;iface eth0 inet manual
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;auto wlan0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#allow-hotplug wlan0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;auto wlan1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#allow-hotplug wlan1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;iface wlan1 inet manual
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;iface wlan0 inet static
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  address 1.1.1.1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  netmask 255.255.255.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  pre-up sudo iptables -t nat -A PREROUTING -i wlan0 -p tcp -j DNAT --to-destination 1.1.1.1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  pre-up sudo python /home/pi/ka-lite/ka-lite-pi-scripts/redirect_port80_to_port8008.py &amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And I modified &lt;code&gt;/etc/default/ifplugd&lt;/code&gt; to only include &lt;code&gt;eth0&lt;/code&gt;, so that the pi does not attempt to join any wireless networks itself:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo nano /etc/default/ifplugd
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;INTERFACES=&amp;#34;eth0&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;HOTPLUG_INTERFACES=&amp;#34;eth0&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ARGS=&amp;#34;-q -f -u0 -d10 -w -I&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SUSPEND_ACTION=&amp;#34;stop&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And then reboot:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo reboot
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Broadcast message from root@raspberrypi (pts/0) (Thu Jun 11 11:05:46 2015):
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;The system is going down for reboot NOW!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;see-if-its-all-working&#34;&gt;See if it&amp;rsquo;s all working
&lt;/h2&gt;&lt;p&gt;Disregard the old addresses once you&amp;rsquo;ve done the above steps, and run &lt;code&gt;ifconfig&lt;/code&gt; to find out about addresses after rebooting.&lt;/p&gt;
&lt;p&gt;The pi broadcasts a passwordless wireless network called &amp;ldquo;kalite&amp;rdquo;, and all DNS lookups point to 1.1.1.1.&lt;/p&gt;
&lt;p&gt;This means in a web browser, you can just load a URL like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;http://kalite
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;platforms&#34;&gt;Platforms
&lt;/h2&gt;&lt;p&gt;On a laptop in range, the network appeared once the pi booted:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-06-raspberry-pi-ka-lite-wireless-deployment/2015-06-kalite01-wifi.png&#34;
	width=&#34;740&#34;
	height=&#34;495&#34;
	srcset=&#34;https://mike42.me/blog/2015-06-raspberry-pi-ka-lite-wireless-deployment/2015-06-kalite01-wifi_hu_a59d37e843c20101.png 480w, https://mike42.me/blog/2015-06-raspberry-pi-ka-lite-wireless-deployment/2015-06-kalite01-wifi_hu_b6d1daa9ff71b776.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;149&#34;
		data-flex-basis=&#34;358px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The network connected without a password:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-06-raspberry-pi-ka-lite-wireless-deployment/2015-06-kalite01-wifi-02.png&#34;
	width=&#34;740&#34;
	height=&#34;495&#34;
	srcset=&#34;https://mike42.me/blog/2015-06-raspberry-pi-ka-lite-wireless-deployment/2015-06-kalite01-wifi-02_hu_cdc9a1c2aea4c5bb.png 480w, https://mike42.me/blog/2015-06-raspberry-pi-ka-lite-wireless-deployment/2015-06-kalite01-wifi-02_hu_50a711122b2efc93.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;149&#34;
		data-flex-basis=&#34;358px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;And the connection info for the client computer is being checked in the background:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-06-raspberry-pi-ka-lite-wireless-deployment/2015-06-kalite01-wifi-03.png&#34;
	width=&#34;1366&#34;
	height=&#34;768&#34;
	srcset=&#34;https://mike42.me/blog/2015-06-raspberry-pi-ka-lite-wireless-deployment/2015-06-kalite01-wifi-03_hu_edb28f5d10f4b4c8.png 480w, https://mike42.me/blog/2015-06-raspberry-pi-ka-lite-wireless-deployment/2015-06-kalite01-wifi-03_hu_2068d350ce1af7ac.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Once the computer gets a lease from DHCP, the URL loads, and the interface works as expected:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-06-raspberry-pi-ka-lite-wireless-deployment/2015-06-kalite01-wifi-04.png&#34;
	width=&#34;923&#34;
	height=&#34;583&#34;
	srcset=&#34;https://mike42.me/blog/2015-06-raspberry-pi-ka-lite-wireless-deployment/2015-06-kalite01-wifi-04_hu_e0e989686e21f990.png 480w, https://mike42.me/blog/2015-06-raspberry-pi-ka-lite-wireless-deployment/2015-06-kalite01-wifi-04_hu_278926ad4598154b.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;158&#34;
		data-flex-basis=&#34;379px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Tested on Android, the player and navigation worked in a similar way:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-06-raspberry-pi-ka-lite-wireless-deployment/2015-06-kalite-droid.gif&#34;
	width=&#34;300&#34;
	height=&#34;533&#34;
	
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;56&#34;
		data-flex-basis=&#34;135px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;KA Lite&amp;rsquo;s media player doesn&amp;rsquo;t seem to require anything other than a web browser. Either Chrome or Firefox seem to be suitable choices.&lt;/p&gt;
&lt;h2 id=&#34;debug-zone&#34;&gt;Debug zone
&lt;/h2&gt;&lt;p&gt;Some useful commands for debugging are shown below.&lt;/p&gt;
&lt;p&gt;List USB devices, for debugging the wireless adapter:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lsusb
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;List recent errors, for debugging the same thing:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dmesg
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Restart networking, run when changing configuration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;service networking restart
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;note-on-dnsmasq&#34;&gt;Note on dnsmasq
&lt;/h3&gt;&lt;p&gt;Because of the way dnsmasq hijacks lookups to provide the wireless network, the Raspberry pi cannot access the Internet over Ethernet (eg, to download content) while &lt;code&gt;dnsmasq&lt;/code&gt; is running:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo service dnsmasq stop
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can access the web interface at &lt;code&gt;http://1.1.1.1/&lt;/code&gt; while this service is disabled.&lt;/p&gt;
&lt;p&gt;And then start it again when done using the Internet, so that the user-friendly computer name works again:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo service dnsmasq start
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>How to install KA Lite on the Raspberry Pi</title>
        <link>https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi</link>
        <pubDate>Wed, 03 Jun 2015 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi</guid>
        <description>&lt;p&gt;KA Lite is an open source, web-based learning package. Today I&amp;rsquo;ll run through a simple setup which will allow a Raspberry Pi to provide a wireless learning resource server for a classroom, without the Internet.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/dia.png&#34;
	width=&#34;269&#34;
	height=&#34;207&#34;
	srcset=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/dia_hu_c89cd8382866c3b9.png 480w, https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/dia_hu_59826093da655cf8.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;129&#34;
		data-flex-basis=&#34;311px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The Raspberry Pi 2 is a surprisingly powerful single-board computer. You can use it for anything which a computer can do, in a relatively cheap circuit board the size of a credit card:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-rpi-2b.png&#34;
	width=&#34;300&#34;
	height=&#34;180&#34;
	srcset=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-rpi-2b_hu_bc19fe78a0fd8676.png 480w, https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-rpi-2b_hu_ca4dac7753076c4a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;166&#34;
		data-flex-basis=&#34;400px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This setup takes around two hours.&lt;/p&gt;
&lt;h2 id=&#34;materials&#34;&gt;Materials
&lt;/h2&gt;&lt;p&gt;You will need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Raspberry Pi (The Raspberry Pi 2 Model B was used here), with micro SD card, mouse, keyboard, monitor with HDMI.&lt;/li&gt;
&lt;li&gt;A good Micro USB power supply - Many Android phone chargers will be suitable.&lt;/li&gt;
&lt;li&gt;A computer which can write to micro SD cards. If your computer has an SD card slot, get an SD-to-Micro-SD adapter for it.&lt;/li&gt;
&lt;li&gt;A wired network with Internet for the setup&lt;/li&gt;
&lt;li&gt;A USB wireless network adapter such as WiPi for deployment.&lt;/li&gt;
&lt;li&gt;Any WiFi-enabled device for testing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;install-raspbian&#34;&gt;Install Raspbian
&lt;/h2&gt;&lt;p&gt;Raspbian is an operating system for the Pi, and is the perfect choice for embedded server setups like this. You need to write the image to the Micro SD card.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Obtain the image from &lt;a class=&#34;link&#34; href=&#34;https://www.raspberrypi.org/downloads/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://www.raspberrypi.org/downloads/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;This is zipped, so extract it to get the real image file.&lt;/li&gt;
&lt;li&gt;Write the disk image to the SD
&lt;ul&gt;
&lt;li&gt;Windows: Fetch a copy of &amp;ldquo;Win32 Disk Imager&amp;rdquo; to write this file to the SD card.&lt;/li&gt;
&lt;li&gt;Linux or Mac: Use &lt;code&gt;dd&lt;/code&gt; (found in the terminal) to write to the card — guide available &lt;a class=&#34;link&#34; href=&#34;http://elinux.org/RPi_Easy_SD_Card_Setup#Using_system_tools_.28mostly_graphical_interface.29&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;here&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Boot the Pi, with mouse, keyboard, HDMI, and wired network. If it doesn&amp;rsquo;t work, remove any cable converters (use HDMI direct to monitor), and if it still doesn&amp;rsquo;t work, then the SD card was not correctly imaged.&lt;/li&gt;
&lt;li&gt;Expand root filesystem, set your password, and enable &amp;ldquo;boot to desktop&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;After reboot, you should have a desktop. Click the black terminal icon to get to work.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;install-some-things&#34;&gt;Install some things
&lt;/h2&gt;&lt;p&gt;From the terminal, run these commands:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get update
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get dist-upgrade
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install chromium python-m2crypto
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This checks for new software (&lt;code&gt;update&lt;/code&gt;), upgrades anything necessary (&lt;code&gt;dist-upgrade&lt;/code&gt;), and then installs two packages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;python-m2crypto&lt;/code&gt; — this will help speed up KA Lite a bit by helping out with encryption.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chromium&lt;/code&gt; — this is the open source upstream of Google Chrome, and it&amp;rsquo;s worth installing so that you can look things up as you go, and test things locally.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If everything goes to plan, you should now be able to find Chrome on the menu and navigate the web.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-kalite-rpi-chrome.png&#34;
	width=&#34;1920&#34;
	height=&#34;1080&#34;
	srcset=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-kalite-rpi-chrome_hu_a488ceb82731edee.png 480w, https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-kalite-rpi-chrome_hu_c6c9b7ef56372b1b.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;install-ka-lite&#34;&gt;Install KA Lite
&lt;/h2&gt;&lt;p&gt;&lt;em&gt;These steps are a shortened version of &lt;a class=&#34;link&#34; href=&#34;https://learningequality.org/docs/installguide/install_rasp_pi.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;the official guide&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Once Raspbian is running, these commands will download &amp;amp; install KA Lite:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone https://github.com/learningequality/ka-lite.git
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cd ka-lite/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./setup_unix.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The download is 150MB, so allow a few minutes. The installer then prompts for a few questions, like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Do you wish to download the assessment package now?&amp;rdquo; — Say &lt;strong&gt;yes&lt;/strong&gt;, it fetches another 500MB.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Do you wish to set the KA Lite server to run in the background automatically when you start this computer?&amp;rdquo; — say &amp;ldquo;y&amp;rdquo;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At the end, you will be given a command to start the server, which you should type in as well:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/home/pi/ka-lite/bin/kalite start
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once it starts (it will take a while!), it will give you &lt;em&gt;two web addresses&lt;/em&gt;. One of them is local to the computer (127.x), and the other will work from other computers on the network. Write both of them down!&lt;/p&gt;
&lt;p&gt;The install &amp;amp; start-up together will look like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-03-kalite-install1.gif&#34;
	width=&#34;415&#34;
	height=&#34;270&#34;
	
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;153&#34;
		data-flex-basis=&#34;368px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;test-it-out-locally&#34;&gt;Test it out locally
&lt;/h2&gt;&lt;p&gt;Open up Chromium, and navigate to one of the addresses that the installer suggested.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-03-kalite-1.png&#34;
	width=&#34;1044&#34;
	height=&#34;817&#34;
	srcset=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-03-kalite-1_hu_957f09728dceb33b.png 480w, https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-03-kalite-1_hu_368b66bcdfa9ec69.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;127&#34;
		data-flex-basis=&#34;306px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Log in, using the details provided during the installation.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-03-kalite-2.png&#34;
	width=&#34;1044&#34;
	height=&#34;817&#34;
	srcset=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-03-kalite-2_hu_1f1f39db0c79e9fd.png 480w, https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-03-kalite-2_hu_f2b45480e1733d60.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;127&#34;
		data-flex-basis=&#34;306px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Click on &amp;ldquo;Manage&amp;rdquo;, then &amp;ldquo;Videos&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-03-kalite-3.png&#34;
	width=&#34;1044&#34;
	height=&#34;817&#34;
	srcset=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-03-kalite-3_hu_880fe836c17e08a5.png 480w, https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-03-kalite-3_hu_b3f6c1fbba3a75b7.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;127&#34;
		data-flex-basis=&#34;306px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;KA Lite will prompt for registration, which lets you download content. Use the &amp;ldquo;One click registration&amp;rdquo; on the left, then wait for it to connect.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-03-kalite-4.png&#34;
	width=&#34;1044&#34;
	height=&#34;817&#34;
	srcset=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-03-kalite-4_hu_77ccd61dc658c691.png 480w, https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-03-kalite-4_hu_bc3ff682222e5d25.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;127&#34;
		data-flex-basis=&#34;306px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-03-kalite-5.png&#34;
	width=&#34;1044&#34;
	height=&#34;817&#34;
	srcset=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-03-kalite-5_hu_177d3862cfa5520c.png 480w, https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-03-kalite-5_hu_82e368cacfd56d57.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;127&#34;
		data-flex-basis=&#34;306px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Use the &lt;strong&gt;Videos&lt;/strong&gt; section to fetch something. Here we fetch something from the ancient art &amp;amp; culture section:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-03-kalite-6.png&#34;
	width=&#34;1044&#34;
	height=&#34;817&#34;
	srcset=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-03-kalite-6_hu_b54025d471d3ee24.png 480w, https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-03-kalite-6_hu_63c3c28d3122ac62.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;127&#34;
		data-flex-basis=&#34;306px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Wait a few minutes before moving to the next section: The video downloads in the background.&lt;/p&gt;
&lt;h2 id=&#34;access-over-the-network&#34;&gt;Access over the network
&lt;/h2&gt;&lt;p&gt;From some other device which is on the same network, enter the web address that was given at the end of the installer (ignore the address which starts with 127.x — it won&amp;rsquo;t work between two computers):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;http://(IP address):8008/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;From the browser, let&amp;rsquo;s test it out. Click over to Learn, and navigate to the video you just downloaded. It should display, so we can learn about those Egyptian artifacts:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-03-kalite-7.png&#34;
	width=&#34;1111&#34;
	height=&#34;555&#34;
	srcset=&#34;https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-03-kalite-7_hu_4afc1eb91cc28d29.png 480w, https://mike42.me/blog/2015-06-how-to-install-ka-lite-on-the-raspberry-pi/2015-06-03-kalite-7_hu_9865719e90da399b.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;200&#34;
		data-flex-basis=&#34;480px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This setup would be complete if you want to run on a wired network - you can simply bookmark this address on each computer which needs to use it, and manage it through the web.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Next post in this series:&lt;/strong&gt; &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2015-06-raspberry-pi-ka-lite-wireless-deployment&#34; &gt;Raspberry Pi KA Lite wireless deployment&lt;/a&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Howto: QR Codes on receipts with escpos-php</title>
        <link>https://mike42.me/blog/2015-04-howto-qrcodes-on-receipts-with-escpos-php</link>
        <pubDate>Sun, 26 Apr 2015 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2015-04-howto-qrcodes-on-receipts-with-escpos-php</guid>
        <description>&lt;p&gt;ESC/POS is a binary protocol for speaking to receipt printers. It contains a command for printing QR Codes on compatible printers. The PHP library &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;escpos-php&lt;/a&gt; is used for generating these commands in PHP. This post will show you how to use it to generate QR codes on your receipt printer.&lt;/p&gt;
&lt;p&gt;For printers which don&amp;rsquo;t support this command, a second option is available: sending the QR code as an image.&lt;/p&gt;
&lt;h2 id=&#34;getting-started&#34;&gt;Getting started
&lt;/h2&gt;&lt;p&gt;First up, you need your receipt printer to be working with escpos-php. Here are some resources about how to go about that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/escpos-php on GitHub&lt;/a&gt; (the most up-to-date reference)&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/what-is-escpos-and-how-do-i-use-it&#34; &gt;What is ESC/POS, and how do I use it?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2014-10-26-setting-up-an-epson-receipt-printer&#34; &gt;Setting up an Epson receipt printer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2015-03-getting-a-usb-receipt-printer-working-on-linux&#34; &gt;Getting a USB receipt printer working on Linux&lt;/a&gt; (or &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows&#34; &gt;Windows&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;option-1-direct-printing&#34;&gt;Option 1: Direct printing
&lt;/h2&gt;&lt;p&gt;This method sends QR codes directly. From the documentation, the syntax for this command is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;qrCode($content, $ec, $size, $model)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Print the given data as a QR code on the printer.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;string $content&lt;/code&gt;: The content of the code. Numeric data will be more efficiently compacted.&lt;/li&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;int $ec&lt;/code&gt; Error-correction level to use. One of &lt;code&gt;Printer::QR_ECLEVEL_L&lt;/code&gt; (default), &lt;code&gt;Printer::QR_ECLEVEL_M&lt;/code&gt;, &lt;code&gt;Printer::QR_ECLEVEL_Q&lt;/code&gt; or &lt;code&gt;Printer::QR_ECLEVEL_H&lt;/code&gt;. Higher error correction results in a less compact code.&lt;/li&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;int $size&lt;/code&gt;: Pixel size to use. Must be 1-16 (default 3)&lt;/li&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;int $model&lt;/code&gt;: QR code model to use. Must be one of &lt;code&gt;Printer::QR_MODEL_1&lt;/code&gt;, &lt;code&gt;Printer::QR_MODEL_2&lt;/code&gt; (default) or &lt;code&gt;Printer::QR_MICRO&lt;/code&gt; (not supported by all printers).&lt;/li&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;
&lt;p&gt;The below code snippets are directly from &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php/blob/master/example/qr-code.php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;the QR code printing demo&lt;/a&gt;, showing how the output changes with the options given&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;simple&#34;&gt;Simple
&lt;/h3&gt;&lt;p&gt;This is the simplest use, with all default options. QR codes can be aligned in the same way as text or images on the page:&lt;/p&gt;



&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2015-04-qr-01&#34;
      id=&#34;tabs-post-2015-04-qr-01-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2015-04-qr-01-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-howto-qrcodes-on-receipts-with-escpos-php/2015-04-escposqr-01-demo.jpg&#34;
	width=&#34;350&#34;
	height=&#34;184&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-howto-qrcodes-on-receipts-with-escpos-php/2015-04-escposqr-01-demo_hu_d24544a24bd49dd2.jpg 480w, https://mike42.me/blog/2015-04-howto-qrcodes-on-receipts-with-escpos-php/2015-04-escposqr-01-demo_hu_51be1d5a3cb8361a.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;190&#34;
		data-flex-basis=&#34;456px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2015-04-qr-01&#34;
      id=&#34;tabs-post-2015-04-qr-01-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2015-04-qr-01-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Most simple example
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;QR code demo&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$testStr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Testing 123&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;qrCode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testStr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Most simple example&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Demo that alignment is the same as text
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setJustification&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;JUSTIFY_CENTER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;qrCode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testStr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Same example, centred&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setJustification&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3 id=&#34;data-encoding&#34;&gt;Data encoding
&lt;/h3&gt;&lt;p&gt;This is a demonstration of saving different types of data in a code. Numeric data is packed more efficiently than text. Binary data can also be stored.&lt;/p&gt;



&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2015-04-qr-02&#34;
      id=&#34;tabs-post-2015-04-qr-02-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2015-04-qr-02-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-howto-qrcodes-on-receipts-with-escpos-php/2015-04-escposqr-02-dataencoding.jpg&#34;
	width=&#34;350&#34;
	height=&#34;296&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-howto-qrcodes-on-receipts-with-escpos-php/2015-04-escposqr-02-dataencoding_hu_be6ff0a6db4996a0.jpg 480w, https://mike42.me/blog/2015-04-howto-qrcodes-on-receipts-with-escpos-php/2015-04-escposqr-02-dataencoding_hu_d49b06d003851431.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;118&#34;
		data-flex-basis=&#34;283px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2015-04-qr-02&#34;
      id=&#34;tabs-post-2015-04-qr-02-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2015-04-qr-02-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Demo of numeric data being packed more densly
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Data encoding&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$test&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;s2&#34;&gt;&amp;#34;Numeric&amp;#34;&lt;/span&gt;      &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;0123456789012345678901234567890123456789&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;s2&#34;&gt;&amp;#34;Alphanumeric&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;abcdefghijklmnopqrstuvwxyzabcdefghijklmn&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;s2&#34;&gt;&amp;#34;Binary&amp;#34;&lt;/span&gt;       &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_repeat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\0&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;40&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;foreach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$test&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;qrCode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$type\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3 id=&#34;error-correction-levels&#34;&gt;Error correction levels
&lt;/h3&gt;&lt;p&gt;QR codes support four levels of error correction. More error correction results in larger, but more durable codes:&lt;/p&gt;



&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2015-04-qr-03&#34;
      id=&#34;tabs-post-2015-04-qr-03-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2015-04-qr-03-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-howto-qrcodes-on-receipts-with-escpos-php/2015-04-escposqr-03-errorcorrection.jpg&#34;
	width=&#34;350&#34;
	height=&#34;352&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-howto-qrcodes-on-receipts-with-escpos-php/2015-04-escposqr-03-errorcorrection_hu_b2c49accdf19167a.jpg 480w, https://mike42.me/blog/2015-04-howto-qrcodes-on-receipts-with-escpos-php/2015-04-escposqr-03-errorcorrection_hu_9c2e6601d9c0813.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;99&#34;
		data-flex-basis=&#34;238px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2015-04-qr-03&#34;
      id=&#34;tabs-post-2015-04-qr-03-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2015-04-qr-03-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Demo of error correction
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Error correction&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$ec&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;QR_ECLEVEL_L&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;L&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;QR_ECLEVEL_M&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;M&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;QR_ECLEVEL_Q&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Q&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;QR_ECLEVEL_H&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;H&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;foreach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$ec&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$level&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;qrCode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testStr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$level&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Error correction &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$name\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3 id=&#34;code-size&#34;&gt;Code size
&lt;/h3&gt;&lt;p&gt;The defauly codes are quite small. Each pixel can be blown up, up to 16x, using the size option:&lt;/p&gt;



&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2015-04-qr-04&#34;
      id=&#34;tabs-post-2015-04-qr-04-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2015-04-qr-04-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-howto-qrcodes-on-receipts-with-escpos-php/2015-04-escposqr-04-pizelsize.jpg&#34;
	width=&#34;350&#34;
	height=&#34;796&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-howto-qrcodes-on-receipts-with-escpos-php/2015-04-escposqr-04-pizelsize_hu_6c14b1289bb3d9b5.jpg 480w, https://mike42.me/blog/2015-04-howto-qrcodes-on-receipts-with-escpos-php/2015-04-escposqr-04-pizelsize_hu_5b277648046e2ece.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;43&#34;
		data-flex-basis=&#34;105px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2015-04-qr-04&#34;
      id=&#34;tabs-post-2015-04-qr-04-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2015-04-qr-04-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Change size
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Pixel size&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$sizes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;(minimum)&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;(default)&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;mi&#34;&gt;16&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;(maximum)&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;foreach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$sizes&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$label&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;qrCode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testStr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;QR_ECLEVEL_L&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Pixel size &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$size&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$label\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3 id=&#34;qr-models&#34;&gt;QR models
&lt;/h3&gt;&lt;p&gt;QR models have different appearances, storage parameters and physical sizes. The default (Model 2) is most common. The printer used here does not support micro QR codes, and used Model 2 as a fallback.&lt;/p&gt;



&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2015-04-qr-05&#34;
      id=&#34;tabs-post-2015-04-qr-05-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2015-04-qr-05-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-howto-qrcodes-on-receipts-with-escpos-php/2015-04-escposqr-05-qrmodel.jpg&#34;
	width=&#34;350&#34;
	height=&#34;322&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-howto-qrcodes-on-receipts-with-escpos-php/2015-04-escposqr-05-qrmodel_hu_701e5ece706586ef.jpg 480w, https://mike42.me/blog/2015-04-howto-qrcodes-on-receipts-with-escpos-php/2015-04-escposqr-05-qrmodel_hu_6f5c10b7a2e4d2dc.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;108&#34;
		data-flex-basis=&#34;260px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2015-04-qr-05&#34;
      id=&#34;tabs-post-2015-04-qr-05-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2015-04-qr-05-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Change model
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;QR model&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$models&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;QR_MODEL_1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;QR Model 1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;QR_MODEL_2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;QR Model 2 (default)&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;QR_MICRO&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Micro QR code&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;(not supported on all printers)&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;foreach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$models&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$model&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;qrCode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testStr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;QR_ECLEVEL_L&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$model&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$name\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3 id=&#34;note&#34;&gt;Note
&lt;/h3&gt;&lt;p&gt;To run the snippets, you need to initialise the printer, and define a &lt;code&gt;title()&lt;/code&gt; function to print headings, like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Demonstration of available options on the qrCode() command */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// ....
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Cut &amp;amp; close
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Escpos&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectPrintMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;MODE_DOUBLE_HEIGHT&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;MODE_DOUBLE_WIDTH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectPrintMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;option-2-printing-codes-as-images&#34;&gt;Option 2: Printing codes as images
&lt;/h2&gt;&lt;p&gt;Not all printers can generate QR codes natively. The work-around is to generate a QR code as an image on the computer, and then send that image to the printer. This is slightly slower, so if you print a lot of codes, you should consider upgrading your printer.&lt;/p&gt;
&lt;p&gt;First up, fetch a copy of &lt;a class=&#34;link&#34; href=&#34;http://phpqrcode.sourceforge.net/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;phpqrcode&lt;/a&gt; and generate some codes. I wont attempt to document the whole library here, but in short, it supports most of the same features as the native QR command. To generate a code, you simply use &lt;code&gt;QRcode::png&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require_once&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;phpqrcode/qrlib.php&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;QRcode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;png&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;testing123&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;test.png&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;L&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To print a PNG image, use the &lt;code&gt;bitImage()&lt;/code&gt; command (the graphics command is also only available on newer printers):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\EscposImage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$img&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;EscposImage&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;load&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;test.png&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Load image
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Add connector to your printer here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;bitImage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$img&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Code printed from image&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A more sophisticated way to hack in phpqrcode would be to add this new code as a different implementaton of the &lt;code&gt;qrCode&lt;/code&gt; function, which I&amp;rsquo;ve done before. Other improvements below are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use temporary files to avoid some potential issues with concurrency and writing files in the working directory&lt;/li&gt;
&lt;li&gt;Where possible, expand the code on the printer, to send less data&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require_once&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;phpqrcode/qrlib.php&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;EscposQrImgPrinter&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;extends&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;qrCode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$content&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$ec&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;QR_ECLEVEL_L&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$model&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;QR_MODEL_2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;c1&#34;&gt;// Validate inputs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;nx&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;validateString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$content&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__FUNCTION__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nx&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;validateInteger&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$ec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__FUNCTION__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nx&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;validateInteger&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;16&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__FUNCTION__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nv&#34;&gt;$model&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;QR_MODEL_2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Only Model 2 supported in phpqrcode, change back to it.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;nv&#34;&gt;$sizeMod&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Optimisation to enlarge codes on the priner, sending 1/4 of the data.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;			&lt;span class=&#34;nv&#34;&gt;$size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;nv&#34;&gt;$sizeMod&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;IMG_DOUBLE_HEIGHT&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;IMG_DOUBLE_WIDTH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;c1&#34;&gt;// Map error-correction to phpqrcode levels
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;nv&#34;&gt;$ecMap&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;QR_ECLEVEL_L&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;L&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;nx&#34;&gt;QR_ECLEVEL_M&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;M&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;nx&#34;&gt;QR_ECLEVEL_Q&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;Q&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;nx&#34;&gt;QR_ECLEVEL_H&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;H&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;c1&#34;&gt;// Create QR code in temp file, and print it.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;		&lt;span class=&#34;nv&#34;&gt;$tmpfname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;tempnam&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sys_get_temp_dir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;escpos-php&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nx&#34;&gt;QRcode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;png&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;testing123&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$tmpfname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$ecMap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$ec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nv&#34;&gt;$img&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;EscposImage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$tmpfname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;bitImage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$img&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$sizeMod&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nx&#34;&gt;unlink&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$tmpfname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This new class uses phpqrcode in the background, but can be accessed with the same function calls as the parent class:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;EscposQrImgPrinter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$testStr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Testing 123&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;qrCode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$testStr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Most simple example&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The only visible difference between the two implementations is a few pixels of spacing below the image.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Deprecated Google API&#39;s: What you need to know</title>
        <link>https://mike42.me/blog/2015-04-deprecated-google-apis-what-you-need-to-know</link>
        <pubDate>Mon, 20 Apr 2015 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2015-04-deprecated-google-apis-what-you-need-to-know</guid>
        <description>&lt;p&gt;In less than a day, a &lt;a class=&#34;link&#34; href=&#34;http://googleappsdeveloper.blogspot.com.au/2014/12/reminder-to-migrate-to-updated-google.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;whole series of old Google APIs&lt;/a&gt; are being switched off.&lt;/p&gt;
&lt;p&gt;If you are running any of those API&amp;rsquo;s, then whilst this is bad news, you&amp;rsquo;ve had several years to upgrade (for example, the Provisioning API features have now been replaced by the Admin SDK). However, one of the API&amp;rsquo;s not mentioned on the linked page is the old &lt;a class=&#34;link&#34; href=&#34;https://developers.google.com/identity/protocols/AuthForInstalledApps&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;ClientLogin API&lt;/a&gt;, which will also stop working on April 20.&lt;/p&gt;
&lt;p&gt;ClientLogin involves directly sending a username and password to Google, and then receiving a login token back. There are two main categories of people who use the ClientLogin API which this post is targeted at:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Developers who haven&amp;rsquo;t got a handle on OAuth yet.&lt;/li&gt;
&lt;li&gt;Developers using client libraries for the Google Data APIs. These APIs themselves are not deprecated, but may be using a deprecated login process.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your use case involves users actually entering their username and password, then this post won&amp;rsquo;t help (&lt;a class=&#34;link&#34; href=&#34;https://developers.google.com/identity/protocols/OAuth2InstalledApp&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;but this page will&lt;/a&gt;), but if you have an installed script which runs administrative functions on your domain, then read on, as it&amp;rsquo;s quite easy to retrofit your scripts with an OAuth2 service account.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-a-service-account&#34;&gt;Setting up a service account
&lt;/h2&gt;&lt;p&gt;Service accounts are designed for server-side use (ie, no browser), and replace using ClientLogin to authenticate as a super-admin for the domain.&lt;/p&gt;
&lt;p&gt;First, log in to the developer console (&lt;a class=&#34;link&#34; href=&#34;https://console.developers.google.com&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;console.developers.google.com&lt;/a&gt;), and create a new project, then jump to the credentials menu. Create and download a &lt;code&gt;p12&lt;/code&gt; private key.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-deprecated-google-apis-what-you-need-to-know/2015-04-01google-cred.png&#34;
	width=&#34;211&#34;
	height=&#34;179&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-deprecated-google-apis-what-you-need-to-know/2015-04-01google-cred_hu_c56c56ee985e0f79.png 480w, https://mike42.me/blog/2015-04-deprecated-google-apis-what-you-need-to-know/2015-04-01google-cred_hu_6a773ba7c5f8f5eb.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;117&#34;
		data-flex-basis=&#34;282px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-deprecated-google-apis-what-you-need-to-know/2015-04-02google-generate.png&#34;
	width=&#34;963&#34;
	height=&#34;172&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-deprecated-google-apis-what-you-need-to-know/2015-04-02google-generate_hu_9f9f6f7e43f44e61.png 480w, https://mike42.me/blog/2015-04-deprecated-google-apis-what-you-need-to-know/2015-04-02google-generate_hu_d13d9e1f91554b7a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;559&#34;
		data-flex-basis=&#34;1343px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Now under &amp;ldquo;Manage this Domain&amp;rdquo;, locate the advanced security options, and add a &lt;strong&gt;delegation&lt;/strong&gt; for your new service account for one or more &lt;strong&gt;scopes&lt;/strong&gt;. This allows the service account to access to a given API and act on behalf of users. As an example, the next section uses the Email Settings API, which has this scope:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;https://apps-apis.google.com/a/feeds/emailsettings/2.0/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And it&amp;rsquo;s added like so:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-deprecated-google-apis-what-you-need-to-know/2015-04-03security.png&#34;
	width=&#34;144&#34;
	height=&#34;150&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-deprecated-google-apis-what-you-need-to-know/2015-04-03security_hu_e715941f2520f267.png 480w, https://mike42.me/blog/2015-04-deprecated-google-apis-what-you-need-to-know/2015-04-03security_hu_dc0a4c0e1d39ca74.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;96&#34;
		data-flex-basis=&#34;230px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-deprecated-google-apis-what-you-need-to-know/2015-04-04advanced.png&#34;
	width=&#34;740&#34;
	height=&#34;101&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-deprecated-google-apis-what-you-need-to-know/2015-04-04advanced_hu_767362cc30acb00.png 480w, https://mike42.me/blog/2015-04-deprecated-google-apis-what-you-need-to-know/2015-04-04advanced_hu_28fca4dd1b534691.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;732&#34;
		data-flex-basis=&#34;1758px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-deprecated-google-apis-what-you-need-to-know/2015-04-05-api.png&#34;
	width=&#34;769&#34;
	height=&#34;274&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-deprecated-google-apis-what-you-need-to-know/2015-04-05-api_hu_d67c2ae3fadb7896.png 480w, https://mike42.me/blog/2015-04-deprecated-google-apis-what-you-need-to-know/2015-04-05-api_hu_330fc8eef3455c34.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;280&#34;
		data-flex-basis=&#34;673px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-deprecated-google-apis-what-you-need-to-know/2015-04-06addscope.png&#34;
	width=&#34;782&#34;
	height=&#34;202&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-deprecated-google-apis-what-you-need-to-know/2015-04-06addscope_hu_c14eb87f06a7c159.png 480w, https://mike42.me/blog/2015-04-deprecated-google-apis-what-you-need-to-know/2015-04-06addscope_hu_eee65979fc0f8581.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;387&#34;
		data-flex-basis=&#34;929px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;example-how-to-retro-fit-a-php-app-with-oauth-2&#34;&gt;Example: How to retro-fit a PHP app with OAuth 2
&lt;/h2&gt;&lt;p&gt;Assuming you already have code which sends requests to an API, all we need to change is the &lt;code&gt;Authorize:&lt;/code&gt; header. A ClientLogin request looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Authorize: GoogleLogin auth=&amp;lt;ClientLogin token&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But an OAuth2 request looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Authorize: Bearer &amp;lt;OAuth token&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can generate a new token for yourself at the &lt;a class=&#34;link&#34; href=&#34;https://developers.google.com/oauthplayground/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;OAuth 2.0 Playground from Google&lt;/a&gt; to make sure your old API&amp;rsquo;s work with the new tokens (they will: any issues are probably permission or user problems).&lt;/p&gt;
&lt;p&gt;So how do you generate one of these tokens for a service account? The best way is to use client libraries for this. In PHP, this is the &lt;a class=&#34;link&#34; href=&#34;https://github.com/google/google-api-php-client&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;google-api-php-client&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This library also has support for newer API&amp;rsquo;s (not older Google Data API&amp;rsquo;s), which you can use to replace your implementation where applicable. For this example, we&amp;rsquo;ll just be getting an access token.&lt;/p&gt;
&lt;p&gt;First up, we need to do some structuring. I&amp;rsquo;ve wrapped old signature code into an abstract &lt;code&gt;EmailSignatureUpdater&lt;/code&gt; class so that I can write two versions: The old &lt;code&gt;ClientLoginEmailSignatureUpdater&lt;/code&gt;, and the new &lt;code&gt;OAuthEmailSignatureUpdater&lt;/code&gt;, differing only by login method and &lt;code&gt;Authorize:&lt;/code&gt; header.&lt;/p&gt;
&lt;p&gt;So here is some ClientLogin code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * Functions dependent on ClientLogin, which will stop working after 2015-04-20.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;ClientLoginEmailSignatureUpdater&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;extends&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;EmailSignatureUpdater&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;     * @param array $conf Configuration for the Google login.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;protected&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;fm&#34;&gt;__construct&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;array&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* Getting account */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$account&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;s1&#34;&gt;&amp;#39;accountType&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;GOOGLE&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;s1&#34;&gt;&amp;#39;Email&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;@&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;domain&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;s1&#34;&gt;&amp;#39;Passwd&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;password&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;s1&#34;&gt;&amp;#39;service&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;apps&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* Log in */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$login&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;login&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;isset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$login&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Auth&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;isset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$login&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Error&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;k&#34;&gt;throw&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Exception&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Google returned &amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$login&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Error&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;k&#34;&gt;throw&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Exception&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Google login failed&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;token&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$login&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Auth&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;     * Perform Google ClientLogin authentication
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;     *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;     * @param array:string $account Account details (see top for components)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;     * @return string Response, including login token.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;private&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;login&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* Log in to google apps */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$tk_ch&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;curl_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;curl_setopt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$tk_ch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;CURLOPT_URL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://www.google.com/accounts/ClientLogin&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;curl_setopt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$tk_ch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;CURLOPT_POST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;curl_setopt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$tk_ch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;CURLOPT_RETURNTRANSFER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;curl_setopt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$tk_ch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;CURLOPT_POSTFIELDS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$responseTxt&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;curl_exec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$tk_ch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;curl_close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$tk_ch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* Parse response (very hack-y but works) */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$responseLines&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;=&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$responseTxt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$lastkey&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$responseLines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nv&#34;&gt;$line&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$responseLines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;cm&#34;&gt;/* First line is just a key */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nv&#34;&gt;$lastkey&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nv&#34;&gt;$vals&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$responseLines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;cm&#34;&gt;/* Split into value and next key */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;nv&#34;&gt;$nextkey&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$vals&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$vals&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;nx&#34;&gt;unset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$vals&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$vals&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;nv&#34;&gt;$nextkey&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nv&#34;&gt;$response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$lastkey&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;implode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$vals&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nv&#34;&gt;$lastkey&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$nextkey&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;protected&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;authorize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;Authorization: GoogleLogin auth=&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;trim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;token&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the part you&amp;rsquo;re probably searching for: how to get an access token out of the &lt;code&gt;google-api-php-client&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * New OAuth2 authentication using google-api-php-client to get us logged in instead.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;OAuthEmailSignatureUpdater&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;extends&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;EmailSignatureUpdater&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;protected&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;fm&#34;&gt;__construct&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;array&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;token&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;login&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;private&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;login&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;array&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;require_once&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;dirname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;__FILE__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/vendor/google-api-php-client/src/Google/autoload.php&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// Start client
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nv&#34;&gt;$client&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Google_Client&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$client&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setApplicationName&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Test Application&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// Load key
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nv&#34;&gt;$key&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;file_get_contents&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;key_file&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;throw&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Exception&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Key could not be loaded from file &amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;key_file&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// Set up auth with scopes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nv&#34;&gt;$gauth&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Google_Auth_AssertionCredentials&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;service_account&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;https://apps-apis.google.com/a/feeds/emailsettings/2.0/&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nv&#34;&gt;$key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// sub- pretend to be a user
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// Should probably be the same as the user you logged in as with ClientLogin
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;isset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;sub&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nv&#34;&gt;$gauth&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;sub&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$client&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setAssertionCredentials&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$gauth&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$client&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;getAuth&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;isAccessTokenExpired&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nv&#34;&gt;$client&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;getAuth&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;refreshTokenWithAssertion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$gauth&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$client&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setClientId&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;client_id&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* Save token for later use */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$token&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$client&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;getAccessToken&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$token&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;throw&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Exception&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Google apps login failed!&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$arr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;json_decode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$token&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;isset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$arr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;access_token&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;throw&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Exception&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Google apps login did not return access token!&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$arr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;access_token&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;protected&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;authorize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;Authorization: Bearer &amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;token&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the superclass, we provide a &lt;code&gt;getUpdater()&lt;/code&gt; function to dish out an old or new updater based on the configuration. In future releases, you could just throw an Exception instead of logging in with ClientLogin, as you know it will fail!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * Contains email signature updater methods, with no login method
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;abstract&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;EmailSignatureUpdater&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;     * @var string The login token.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;protected&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$token&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;     * @param array $conf The configuration to use.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;protected&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;abstract&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;fm&#34;&gt;__construct&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;array&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;     * Return authorization header
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;protected&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;abstract&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;authorize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// A series of methods which make raw HTTP requests
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// to https://apps-apis.google.com/a/feeds/emailsettings/2.0/ were
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// located here, and are not relevant to this post.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;     * Based on the configuration, return a signature updater which logs in using the correct API.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;     * 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;     * @param array $conf
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;getUpdater&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;array&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;isset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;isset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;domain&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;isset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;password&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ClientLoginEmailSignatureUpdater&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;isset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;service_account&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;isset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;client_id&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;isset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;key_file&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;OAuthEmailSignatureUpdater&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;throw&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Exception&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Configuration insufficient for loading email signatures. See config.php.example.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To utilise this, you need to change HTTP methods to care less about where their headers come from. I was using cURL for this, but on any library, you need to set the header using the new &lt;code&gt;authorize()&lt;/code&gt; function before you send off the request:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;curl_setopt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$ch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;CURLOPT_HTTPHEADER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;authorize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The idea is that users can simply alter their configuration to pick up the newly supported OAuth, allowing you to shift it from a software problem to an administrative/configuration problem:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Google apps domain config */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Old style ClientLogin usage (deprecated) */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//$config[&amp;#39;google&amp;#39;][&amp;#39;user&amp;#39;] = &amp;#34;admin&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//$config[&amp;#39;google&amp;#39;][&amp;#39;domain&amp;#39;] = &amp;#34;example.com&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//$config[&amp;#39;google&amp;#39;][&amp;#39;password&amp;#39;] = &amp;#34;...&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* New login details for OAuth */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$config&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;google&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;][&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;service_account&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;...@developer.gserviceaccount.com&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$config&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;google&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;][&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;client_id&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;....apps.googleusercontent.com&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$config&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;google&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;][&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;key_file&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;dirname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;__FILE__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/google-key.p12&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$config&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;google&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;][&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;sub&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;admin@example.com&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// optional
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Within your application, you then construct a new any-authentication object based on the configuration, and call its old methods as normal:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$updater&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;EmailSignatureUpdater&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;getUpdater&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$config&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;google&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$updater&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;doThing&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;param1&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;param2&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;etc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I hope this helps!&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to use a Raspberry Pi as a print server</title>
        <link>https://mike42.me/blog/2015-04-how-to-use-a-raspberry-pi-as-a-print-server</link>
        <pubDate>Thu, 16 Apr 2015 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2015-04-how-to-use-a-raspberry-pi-as-a-print-server</guid>
        <description>&lt;p&gt;This post is designed for people who want to share a simple USB printer, such as &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2015-03-getting-a-usb-receipt-printer-working-on-linux&#34; &gt;this receipt printer&lt;/a&gt;, over the network.&lt;/p&gt;
&lt;p&gt;Usually, you just connect up the printer to the computer like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-how-to-use-a-raspberry-pi-as-a-print-server/2015-04-rpi-printer1.png&#34;
	width=&#34;261&#34;
	height=&#34;60&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-how-to-use-a-raspberry-pi-as-a-print-server/2015-04-rpi-printer1_hu_d562a17178e33910.png 480w, https://mike42.me/blog/2015-04-how-to-use-a-raspberry-pi-as-a-print-server/2015-04-rpi-printer1_hu_f5a7a023f81e29c0.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;435&#34;
		data-flex-basis=&#34;1044px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;But if you are sending the print jobs from a central server, you would instead follow these steps, and hook up a Raspberry Pi near the printer to pass on the print-outs for you:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-how-to-use-a-raspberry-pi-as-a-print-server/2015-04-rpi-printer2.png&#34;
	width=&#34;469&#34;
	height=&#34;63&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-how-to-use-a-raspberry-pi-as-a-print-server/2015-04-rpi-printer2_hu_3ed1d7de218a8682.png 480w, https://mike42.me/blog/2015-04-how-to-use-a-raspberry-pi-as-a-print-server/2015-04-rpi-printer2_hu_a2a7c940e605b409.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;744&#34;
		data-flex-basis=&#34;1786px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This post will show you a very fuss-free way to do this. Because of its simplicity, if you have multiple computers printing (read: you need a server that can spool), or need two-way communication with the printer, then this setup will not be sufficient for your use case.&lt;/p&gt;
&lt;h2 id=&#34;one-off-setup&#34;&gt;One-off setup
&lt;/h2&gt;&lt;p&gt;If your printer is &lt;code&gt;/dev/usb/lp0&lt;/code&gt;, then the command to run is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nohup nc -klp 9100 &amp;gt; /dev/usb/lp0 2&amp;gt; /dev/null&amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There is quite a lot going on in this command, so I&amp;rsquo;m going to break it down into parts and explain what each one does.&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;code&gt;nohup&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;Lets the command keep running after you log out.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;nc -klp 9100&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;Listens on port 9100 (&lt;code&gt;-lp&lt;/code&gt;), and returns to listening after each connection (&lt;code&gt;-k&lt;/code&gt;)&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;&amp;gt; /dev/usb/lp0&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;Redirects any incoming data to the printer device&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;2&amp;gt; /dev/null&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;Suppresses errors by sending them to &lt;code&gt;/dev/null&lt;/code&gt;&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;&amp;amp;&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;Runs the command in the background so that you can keep using the terminal.&lt;/dd&gt;
&lt;/dl&gt;
&lt;h2 id=&#34;run-every-boot&#34;&gt;Run every boot
&lt;/h2&gt;&lt;p&gt;Simply schedule the command in &lt;code&gt;cron&lt;/code&gt; as a &lt;code&gt;@reboot&lt;/code&gt; task.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;crontab -e
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And add the line:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;@reboot nohup nc -klp 9100 &amp;gt; /dev/usb/lp0 2&amp;gt; /dev/null&amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that if you reboot the printer, you will also need to reboot the raspberry pi to get it to reconnect without logging in!&lt;/p&gt;
&lt;h2 id=&#34;send-some-tests&#34;&gt;Send some tests
&lt;/h2&gt;&lt;p&gt;From a computer somewhere else on the network, send a test print-out:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;echo &amp;#34;Hello world&amp;#34; | nc 10.x.x.x 9100
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the target printer is a thermal receipt printer, then you could also use &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/escpos-php&lt;/a&gt; to send it more elaborate commands:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$fp&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;fsockopen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;10.x.x.x&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;9100&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Print a &amp;#34;Hello world&amp;#34; receipt&amp;#34; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Escpos&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$fp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello World!&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;fclose&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$fp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>How to run Tetris on your Raspberry Pi</title>
        <link>https://mike42.me/blog/2015-03-how-to-run-tetris-on-your-raspberry-pi</link>
        <pubDate>Thu, 09 Apr 2015 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2015-03-how-to-run-tetris-on-your-raspberry-pi</guid>
        <description>&lt;p&gt;This is a simple walkthrough on how to install my Tetris clone, &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/blocks&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Blocks&lt;/a&gt;, on a Raspberry Pi.&lt;/p&gt;
&lt;p&gt;On most computers running Debian (or Raspbian in the case of the Raspberry Pi), it&amp;rsquo;s as simple as clone, compile, run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install libncurses5-dev doxygen
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone https://github.com/mike42/blocks
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cd blocks
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./bin/blocks
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you have any issues running this, then you need to fetch a newer version of GCC, as this needs C++11 support to compule (see last section for instructuins).&lt;/p&gt;
&lt;p&gt;But if all goes to plan, you will get something like this in your terminal:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-03-how-to-run-tetris-on-your-raspberry-pi/2015-04-tetris.gif&#34;
	width=&#34;400&#34;
	height=&#34;236&#34;
	
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;169&#34;
		data-flex-basis=&#34;406px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Use the keyboard to control the game:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;Move&lt;/dt&gt;
&lt;dd&gt;Right, down, left&lt;/dd&gt;
&lt;dt&gt;Rotate&lt;/dt&gt;
&lt;dd&gt;Up&lt;/dd&gt;
&lt;dt&gt;Drop&lt;/dt&gt;
&lt;dd&gt;Spacebar&lt;/dd&gt;
&lt;dt&gt;Quit&lt;/dt&gt;
&lt;dd&gt;q&lt;/dd&gt;
&lt;/dl&gt;
&lt;h2 id=&#34;get-a-screen&#34;&gt;Get a screen
&lt;/h2&gt;&lt;p&gt;Basically any project with graphics can benefit from one of these. Simply add on a TFT shield, such as &lt;a class=&#34;link&#34; href=&#34;http://www.adafruit.com/product/1601&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;PiTFT&lt;/a&gt; to create a tiny console:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-03-how-to-run-tetris-on-your-raspberry-pi/2015-04-tetris.jpg&#34;
	width=&#34;2283&#34;
	height=&#34;1314&#34;
	srcset=&#34;https://mike42.me/blog/2015-03-how-to-run-tetris-on-your-raspberry-pi/2015-04-tetris_hu_873733b4926635d3.jpg 480w, https://mike42.me/blog/2015-03-how-to-run-tetris-on-your-raspberry-pi/2015-04-tetris_hu_d3205af5d69baf90.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;173&#34;
		data-flex-basis=&#34;416px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Of course, this is still keyboard-controlled, but with some hacking, I&amp;rsquo;m sure you could map touch events to keyboard actions.&lt;/p&gt;
&lt;h2 id=&#34;troubleshooting-update-gcc&#34;&gt;Troubleshooting: Update GCC
&lt;/h2&gt;&lt;p&gt;The Raspbian spftware image which many Raspberry Pi&amp;rsquo;s have is slightly too old to compile Blocks, which requires C++11 support.&lt;/p&gt;
&lt;p&gt;Luckily, it&amp;rsquo;s very easy to upgrade from &lt;i&gt;wheezy&lt;/i&gt; to &lt;i&gt;jessie&lt;/i&gt; to add it. You know you need to do this if you get this error compiling:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ git clone https://github.com/mike42/blocks
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ make
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir -p bin
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;g++ src/main.cpp src/blocks_game.cpp src/blocks_shape.cpp -o bin/blocks -lcurses -lrt -std=c++11 -Wall
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cc1plus: error: unrecognized command line option ‘-std=c++11’
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cc1plus: error: unrecognized command line option ‘-std=c++11’
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cc1plus: error: unrecognized command line option ‘-std=c++11’
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Makefile:2: recipe for target &amp;#39;default&amp;#39; failed
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make: *** [default] Error 1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Generally this means you don&amp;rsquo;t have GCC 4.8, which is not available in &lt;i&gt;wheezy&lt;/i&gt; edition of Raspian.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ g++ --version
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;g++ (Debian 4.6.3-14+rpi1) 4.6.3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Copyright (C) 2011 Free Software Foundation, Inc.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is free software; see the source for copying conditions.  There is NO
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So to summarise &lt;a class=&#34;link&#34; href=&#34;http://www.raspberrypi.org/forums/viewtopic.php?t=65516&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this thread&lt;/a&gt;, you need to:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nano /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Find this line:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb http://mirrordirector.raspbian.org/raspbian/ wheezy main contrib non-free rpi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And change the word &amp;ldquo;wheezy&amp;rdquo; to &amp;ldquo;jessie&amp;rdquo;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb http://mirrordirector.raspbian.org/raspbian/ jessie main contrib non-free rpi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can then update everything with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get update &amp;amp;&amp;amp; sudo apt-get dist-upgrade
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You are now running the newer &lt;i&gt;jessie&lt;/i&gt; release, which gives you access to the GCC 4.8 package we need:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install g++-4.8
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So we can pick up where we left off, and compile the game:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./bin/blocks
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>Getting a USB receipt printer working on Windows</title>
        <link>https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows</link>
        <pubDate>Wed, 08 Apr 2015 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows</guid>
        <description>&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post is a Windows adaptation of an earlier post, &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2015-03-getting-a-usb-receipt-printer-working-on-linux&#34; &gt;Getting a USB receipt printer working on Linux&lt;/a&gt;, mainly in response to &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php/issues/9&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;these&lt;/a&gt; &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php/issues/14&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;questions&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In this post, I&amp;rsquo;ll step through how to get a USB thermal receipt printer appearing on Windows. The aim of this is to be able to send raw text to the printer, so that we can point a driver such as &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;escpos-php&lt;/a&gt; at it. The printer tested here is once again this Epson TM-T20:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-03-printer-back.jpg&#34;
	width=&#34;3264&#34;
	height=&#34;1928&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-03-printer-back_hu_b781acf3f749364d.jpg 480w, https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-03-printer-back_hu_88880f933c013dcc.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;169&#34;
		data-flex-basis=&#34;406px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-03-printer-top.jpg&#34;
	width=&#34;2460&#34;
	height=&#34;1816&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-03-printer-top_hu_eb82a29bb98b6db0.jpg 480w, https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-03-printer-top_hu_6227b6e59edbc1af.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;135&#34;
		data-flex-basis=&#34;325px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The directions below are for Windows 7, so your mileage may vary if you are on an older or newer version.&lt;/p&gt;
&lt;p&gt;If you have issues following these steps, make sure you can locate your printer in Device Manager, and that it has &amp;ldquo;USB Print Support&amp;rdquo;.&lt;/p&gt;
&lt;h2 id=&#34;add-the-printer&#34;&gt;Add the printer
&lt;/h2&gt;&lt;p&gt;Find &lt;strong&gt;Devices and Printers&lt;/strong&gt; and click &lt;strong&gt;Add a Printer&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-01.png&#34;
	width=&#34;676&#34;
	height=&#34;217&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-01_hu_51fbb525c8b13348.png 480w, https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-01_hu_34f5149212f83785.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;311&#34;
		data-flex-basis=&#34;747px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-02.png&#34;
	width=&#34;514&#34;
	height=&#34;313&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-02_hu_4d051c9de3cc9720.png 480w, https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-02_hu_d3a024dc810afee3.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;164&#34;
		data-flex-basis=&#34;394px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Add it as a &lt;strong&gt;Local printer&lt;/strong&gt;, using the USB virtual port, probably &lt;strong&gt;USB0001&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-03.png&#34;
	width=&#34;628&#34;
	height=&#34;458&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-03_hu_2fab3e9a5cb99bb3.png 480w, https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-03_hu_6da6ae83e65bc51d.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;137&#34;
		data-flex-basis=&#34;329px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-04.png&#34;
	width=&#34;628&#34;
	height=&#34;458&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-04_hu_c65c54c5c245345c.png 480w, https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-04_hu_4e64795d5cc162f1.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;137&#34;
		data-flex-basis=&#34;329px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Use the &lt;strong&gt;Generic / Text Only&lt;/strong&gt; driver.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-05.png&#34;
	width=&#34;628&#34;
	height=&#34;458&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-05_hu_a2fd350e6115a10.png 480w, https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-05_hu_9fb381d210bba992.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;137&#34;
		data-flex-basis=&#34;329px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Name the printer whatever you like, and then share it under the same name:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-06.png&#34;
	width=&#34;628&#34;
	height=&#34;458&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-06_hu_7686ccc780695be.png 480w, https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-06_hu_931db132ff36a814.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;137&#34;
		data-flex-basis=&#34;329px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-07.png&#34;
	width=&#34;628&#34;
	height=&#34;458&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-07_hu_484206d664442fc7.png 480w, https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-07_hu_fc13a634169dc16c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;137&#34;
		data-flex-basis=&#34;329px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;At this point, it should pop up in the window in the background, and also prompt you to &lt;strong&gt;Print a test page&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-08.png&#34;
	width=&#34;612&#34;
	height=&#34;317&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-08_hu_5fc25076f3392fa1.png 480w, https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-08_hu_d5db115cf9cd17e8.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;193&#34;
		data-flex-basis=&#34;463px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-09.png&#34;
	width=&#34;628&#34;
	height=&#34;458&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-09_hu_8b7033a28e97f837.png 480w, https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-09_hu_98bfbee3d19da7a0.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;137&#34;
		data-flex-basis=&#34;329px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The test print is plain-text, and depending on your printer, will look something like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-10.jpg&#34;
	width=&#34;300&#34;
	height=&#34;751&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-10_hu_33eed952b76d60fa.jpg 480w, https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-10_hu_4d2fe838a5c500e0.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;39&#34;
		data-flex-basis=&#34;95px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Finally, you need to verify that your printer can be accessed locally, by typing &lt;code&gt;\\localhost&lt;/code&gt; into Windows Explorer. If all goes to plan, you will see the new printer there too:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-11.png&#34;
	width=&#34;382&#34;
	height=&#34;172&#34;
	srcset=&#34;https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-11_hu_cc27a408315121c2.png 480w, https://mike42.me/blog/2015-04-getting-a-usb-receipt-printer-working-on-windows/2015-04-windowsusb-11_hu_580484df3e23c07d.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;222&#34;
		data-flex-basis=&#34;533px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;run-a-command-line-test-print&#34;&gt;Run a command-line test print
&lt;/h2&gt;&lt;p&gt;We now know that your printer is working, and can be accessed via its share name (even locally).&lt;/p&gt;
&lt;p&gt;Test printing from the command-line. Fire up &lt;code&gt;cmd.exe&lt;/code&gt; and try to send it some text to verify that it&amp;rsquo;s working:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;echo &amp;#34;Hello World&amp;#34; &amp;gt; testfile
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;print /D:&amp;#34;\\%COMPUTERNAME%\Receipt Printer&amp;#34; testfile
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;del testfile
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;printing-something-useful&#34;&gt;Printing something useful
&lt;/h2&gt;&lt;p&gt;This is where you start to see real results. Receipt printers are not just for printing plain-text. Many of them support a standard called ESC/POS, which contains formatting commands.&lt;/p&gt;
&lt;p&gt;The snippet below, from &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2014-10-26-setting-up-an-epson-receipt-printer&#34; &gt;this earlier post&lt;/a&gt;, generates some basic ESC/POS commands.&lt;/p&gt;
&lt;p&gt;Install PHP if you don&amp;rsquo;t have it already, and call the below code &lt;code&gt;foo.php&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* ASCII constants */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ESC&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x1b&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;GS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x1d&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;NUL&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x00&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Output an example receipt */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ESC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;@&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Reset to defaults
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ESC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;E&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Bold
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;FOO CORP Ltd.&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Company
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ESC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;E&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Not Bold
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ESC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Blank line
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Receipt for whatever&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Print text
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ESC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 4 Blank lines
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Bar-code at the end */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ESC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Centered printing
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;GS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;k&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;987654321&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;NUL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Print barcode
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ESC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Blank line
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;987654321&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Print number
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;GS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;V&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x41&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Cut
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You would send generated commands to the printer like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;php foo.php &amp;gt; testfile
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;print /D:&amp;#34;\\%COMPUTERNAME%\Receipt Printer&amp;#34; testfile
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rm testfile
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;scaling-this-up&#34;&gt;Scaling this up
&lt;/h2&gt;&lt;p&gt;The correct ESC/POS codes are quite tricky to generate with manually, which is why I put together the escpos-php driver. You can find more information on that at:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/escpos-php&lt;/a&gt; on GitHub&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/what-is-escpos-and-how-do-i-use-it&#34; &gt;What is ESC/POS, and how do I use it?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A simple &amp;ldquo;Hello World&amp;rdquo; receipt to your Windows shared printer would be scripted as (call this one &lt;code&gt;foo2.php&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\WindowsPrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;try&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Enter the share name for your USB printer here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;WindowsPrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Receipt Printer&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Print a &amp;#34;Hello world&amp;#34; receipt&amp;#34; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello World!&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Close printer */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;catch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Exception&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Couldn&amp;#39;t print to this printer: &amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;getMessage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This would be sent to the printer by loading it from the web, or running the script on the command-line:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;php foo2.php
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The full ESC/POS snippet with formatting, coded up with escpos-php, would look like this (call this one &lt;code&gt;foo3.php&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\WindowsPrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;try&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Enter the share name for your USB printer here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;WindowsPrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Receipt Printer&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Print some bold text */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setEmphasis&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;FOO CORP Ltd.&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setEmphasis&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Receipt for whatever&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Bar-code at the end */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setJustification&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;JUSTIFY_CENTER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;barcode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;987654321&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Close printer */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;catch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Exception&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Couldn&amp;#39;t print to this printer: &amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;getMessage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And again, this could be executed by loading the page through the web, or invoking the command directly:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;php foo3.php
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>How to empty your local user account</title>
        <link>https://mike42.me/blog/2015-04-how-to-empty-your-local-user-account</link>
        <pubDate>Sat, 04 Apr 2015 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2015-04-how-to-empty-your-local-user-account</guid>
        <description>&lt;p&gt;If you&amp;rsquo;re not going to use a user account on your computer again, but can&amp;rsquo;t delete it for some reason, then emptying it is the next best thing to do.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Word of warning:&lt;/strong&gt; Save anything you want to keep before you start deleting things. These are destructive commands which delete all of the files and settings in the current user&amp;rsquo;s profile. If you are at all unsure, consider using a file browser to clear out the profile instead.&lt;/p&gt;
&lt;p&gt;Windows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cd %USERPROFILE%
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;del /A / F /Q /S .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Linux or Mac:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cd ~
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rm -Rf .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will make sure that the disused account no-longer wastes any disk space.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Getting a USB receipt printer working on Linux</title>
        <link>https://mike42.me/blog/2015-03-getting-a-usb-receipt-printer-working-on-linux</link>
        <pubDate>Sun, 08 Mar 2015 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2015-03-getting-a-usb-receipt-printer-working-on-linux</guid>
        <description>&lt;p&gt;In this post, I&amp;rsquo;ll step through how to get a thermal receipt printer with USB interface appearing on Linux. The aim of this is to be able to point a driver such as &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;escpos-php&lt;/a&gt; at the device. The printer used here is an Epson TM-T20, which is very common in point-of-sale environments.&lt;/p&gt;
&lt;p&gt;I have previously written quite a bit about &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/what-is-escpos-and-how-do-i-use-it&#34; &gt;how to use thermal receipt printer protocols&lt;/a&gt;, but the previous printer I covered &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2014-10-26-setting-up-an-epson-receipt-printer&#34; &gt;had only a network interface&lt;/a&gt;, not USB like this one:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-03-getting-a-usb-receipt-printer-working-on-linux/2015-03-printer-back.jpg&#34;
	width=&#34;3264&#34;
	height=&#34;1928&#34;
	srcset=&#34;https://mike42.me/blog/2015-03-getting-a-usb-receipt-printer-working-on-linux/2015-03-printer-back_hu_b781acf3f749364d.jpg 480w, https://mike42.me/blog/2015-03-getting-a-usb-receipt-printer-working-on-linux/2015-03-printer-back_hu_88880f933c013dcc.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;169&#34;
		data-flex-basis=&#34;406px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2015-03-getting-a-usb-receipt-printer-working-on-linux/2015-03-printer-top.jpg&#34;
	width=&#34;2460&#34;
	height=&#34;1816&#34;
	srcset=&#34;https://mike42.me/blog/2015-03-getting-a-usb-receipt-printer-working-on-linux/2015-03-printer-top_hu_eb82a29bb98b6db0.jpg 480w, https://mike42.me/blog/2015-03-getting-a-usb-receipt-printer-working-on-linux/2015-03-printer-top_hu_6227b6e59edbc1af.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;135&#34;
		data-flex-basis=&#34;325px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The directions below are for Debian, but could be adapted for any other Linux.&lt;/p&gt;
&lt;h2 id=&#34;find-the-device-file&#34;&gt;Find the device file
&lt;/h2&gt;&lt;p&gt;Plug in your printer, and check that &lt;code&gt;usblp&lt;/code&gt; sees it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dmesg
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[12724.994550] usb 8-4: new full-speed USB device number 5 using ohci-pci
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[12725.168956] usb 8-4: New USB device found, idVendor=04b8, idProduct=0e03
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[12725.168963] usb 8-4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[12725.168968] usb 8-4: Product: TM-T20
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[12725.168971] usb 8-4: Manufacturer: EPSON
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[12725.168975] usb 8-4: SerialNumber: ....
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[12725.175114] usblp 8-4:1.0: usblp1: USB Bidirectional printer dev 5 if 0 alt 0 proto 2 vid 0x04B8 pid 0x0E03
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This kernel module makes your printer visible as a device file, so that it can be accessed in the old-fashioned way. Find the new device file under &lt;code&gt;/dev/usb&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ls /dev/usb
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In my case, this was &lt;code&gt;/dev/usb/lp1&lt;/code&gt;. The next step is to see if you can write to it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;echo &amp;#34;Hello&amp;#34; &amp;gt;&amp;gt; /dev/usb/lp1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Chances are, you will get a permission denied error at this point, so find out what group the printer is in:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;stat /dev/usb/lp1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Which will show output something like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;File: ‘/dev/usb/lp1’
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Size: 0         	Blocks: 0          IO Block: 4096   character special file
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Device: 5h/5d	Inode: 220997      Links: 1     Device type: b4,1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Access: (0660/crw-rw----)  Uid: (    0/    root)   Gid: (    7/      lp)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This file is owned by group &lt;code&gt;lp&lt;/code&gt; (&amp;ldquo;line printer&amp;rdquo;). If your username was &lt;code&gt;bob&lt;/code&gt;, you would add yourself to this group using:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo usermod -a -G lp bob
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you plan to build a web-based point-of-sale system with this, then also add the &lt;code&gt;www-data&lt;/code&gt; user to that group.&lt;/p&gt;
&lt;p&gt;Now log out and back in, and the previous test should now be working:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;echo &amp;#34;Hello&amp;#34; &amp;gt;&amp;gt; /dev/usb/lp1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;troubleshooting-check-usblp&#34;&gt;Troubleshooting: Check usblp
&lt;/h3&gt;&lt;p&gt;If these steps don&amp;rsquo;t work, then your computer either doesn&amp;rsquo;t have, or isn&amp;rsquo;t using &lt;code&gt;usblp&lt;/code&gt; You&amp;rsquo;ll need to check a few things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Install a different linux-image if the driver is &lt;a class=&#34;link&#34; href=&#34;https://packages.debian.org/search?mode=filename&amp;amp;suite=wheezy&amp;amp;section=all&amp;amp;arch=i386&amp;amp;searchon=contents&amp;amp;keywords=usblp.ko&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;not on your computer&lt;/a&gt; at all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;modprobe&lt;/code&gt; or &lt;code&gt;insmod usblp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;blacklist a vendor driver which has claimed the interface.&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;lsusb -v&lt;/code&gt; and &lt;code&gt;usb-devices&lt;/code&gt; (look for &lt;code&gt;driver=&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;printing-something-useful&#34;&gt;Printing something useful
&lt;/h2&gt;&lt;p&gt;As a duplicated section from my &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2014-10-26-setting-up-an-epson-receipt-printer&#34; &gt;earlier post&lt;/a&gt;, the printer uses ESC/POS, which means it accepts plaintext with some special commands for formatting.&lt;/p&gt;
&lt;p&gt;A simple receipt-generator, &lt;code&gt;foo.php&lt;/code&gt;, might look like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* ASCII constants */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ESC&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x1b&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;GS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x1d&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;NUL&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x00&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Output an example receipt */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ESC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;@&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Reset to defaults
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ESC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;E&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Bold
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;FOO CORP Ltd.&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Company
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ESC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;E&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Not Bold
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ESC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Blank line
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Receipt for whatever&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Print text
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ESC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 4 Blank lines
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Bar-code at the end */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ESC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Centered printing
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;GS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;k&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;987654321&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;NUL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Print barcode
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ESC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Blank line
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;987654321&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Print number
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;GS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;V&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x41&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Cut
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And you would send it to the printer like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;php foo.php &amp;gt; /dev/usb/lp1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;scaling-this-up&#34;&gt;Scaling this up
&lt;/h2&gt;&lt;p&gt;The codes are quite tricky to work with manually, which is why I put together the escpos-php driver. You can find it at:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/escpos-php&lt;/a&gt; on GitHub&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/what-is-escpos-and-how-do-i-use-it&#34; &gt;What is ESC/POS, and how do I use it?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The previous example would be written using escpos-php as:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Print some bold text */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setEmphasis&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;FOO CORP Ltd.&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setEmphasis&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Receipt for whatever&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Bar-code at the end */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setJustification&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;JUSTIFY_CENTER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;barcode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;987654321&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This would be sent to the printer by loading it from the web, or running the script on the command-line:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;php foo2.php
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>Configure asterisk with wildcard extensions</title>
        <link>https://mike42.me/blog/2015-02-configure-asterisk-with-wildcard-extensions</link>
        <pubDate>Thu, 19 Feb 2015 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2015-02-configure-asterisk-with-wildcard-extensions</guid>
        <description>&lt;p&gt;This post covers a common use case when deploying a phone system: Somebody in the business needs to be able to record voicemail greetings for other people.&lt;/p&gt;
&lt;p&gt;This assumes that you are &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2015-01-02-how-to-set-up-asterisk-in-10-minutes&#34; &gt;already running asterisk&lt;/a&gt;, and that there is already something like this in your Dialplan (&lt;code&gt;extensions.conf&lt;/code&gt;) for users to record a greeting:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Record voicemail greeting&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;exten&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;gt; *,1,AGI(scripts/record-voicemail-greeting.pl);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To run this script &lt;em&gt;as somebody else&lt;/em&gt;, in the phone sense, we just need to change the CallerID before we run it. Some things you&amp;rsquo;ll need to know to do this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;An &amp;ldquo;X&amp;rdquo; in the extension matches any digit&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EXTEN&lt;/code&gt; is a variable holding the current extension&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CALLERID(num)&lt;/code&gt; is another variable, which holds the CallerID number&lt;/li&gt;
&lt;li&gt;&lt;code&gt;${EXTEN:2}&lt;/code&gt; is a &amp;ldquo;substring&amp;rdquo;, which cuts the first two letters off the extension&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With that in mind, if &lt;code&gt;*&lt;/code&gt; records your own voicemail, then &lt;code&gt;**4567&lt;/code&gt; would record &lt;code&gt;4567&lt;/code&gt;&amp;rsquo;s voicemail using this snippet:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Record other person&amp;#39;s voicemail greeting&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;exten&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;gt; **XXXX,1,Set(CALLERID(num)=${EXTEN:2})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;exten&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;gt; **XXXX,2,Goto(*,1)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Of course, you&amp;rsquo;re not likely to want to enable this for the whole business, which is why you can also check the CallerID before you change it. This alternative snippet allows you to record any voicemail greeting, but only if you are calling from 1234.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;; Record other person&amp;#39;s voicemail greeting (if calling from phone 1234)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;exten&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;gt; 1234/**XXXX,1,Set(CALLERID(num)=${EXTEN:2})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;exten&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;gt; 1234/**XXXX,2,Goto(*,1)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>Two ways to back up your Google Apps account</title>
        <link>https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account</link>
        <pubDate>Wed, 11 Feb 2015 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account</guid>
        <description>&lt;p&gt;If you use Gmail or hosted Google Apps, you might be interested in taking a backup of your data, such as emails, Drive documents, and calendar entries. Thankfully, you can usually export copy of your account data using Google Takeout.&lt;/p&gt;
&lt;p&gt;If your hosted Apps account has Takeout disabled, then you can do a backup, it simply has a few extra steps.&lt;/p&gt;
&lt;h2 id=&#34;option-1-google-takeout&#34;&gt;Option 1: Google Takeout
&lt;/h2&gt;&lt;p&gt;This method is nice and simple. Simply go to the &lt;a class=&#34;link&#34; href=&#34;https://www.google.com/settings/takeout&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Data tools - Download your data&lt;/a&gt; page, and select which services you want to export:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-01-google-takeout.png&#34;
	width=&#34;771&#34;
	height=&#34;815&#34;
	srcset=&#34;https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-01-google-takeout_hu_ce2eeadb24fffbfd.png 480w, https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-01-google-takeout_hu_9bb74a33e952c035.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;94&#34;
		data-flex-basis=&#34;227px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;It can be a bit eye-opening to see the amount of data Google has on you (Files, conversations, location history, etc). At this point, click through to &amp;ldquo;Prepare Download&amp;rdquo;. Depending on the size of your account, this may take the duration of a coffee break, a few hours, or even an entire day.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-google-takeout-prepare.png&#34;
	width=&#34;787&#34;
	height=&#34;613&#34;
	srcset=&#34;https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-google-takeout-prepare_hu_51d757ed8fcabb3e.png 480w, https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-google-takeout-prepare_hu_3f18e040e8390474.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;128&#34;
		data-flex-basis=&#34;308px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;If you check the box for it, you&amp;rsquo;ll get an email like this when your Download completes:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-google-archive.png&#34;
	width=&#34;734&#34;
	height=&#34;456&#34;
	srcset=&#34;https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-google-archive_hu_73ce69eab2c07b71.png 480w, https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-google-archive_hu_10a17f16489b5fb9.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;160&#34;
		data-flex-basis=&#34;386px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;And this lets you fetch a single file:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-01-download.png&#34;
	width=&#34;613&#34;
	height=&#34;160&#34;
	srcset=&#34;https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-01-download_hu_ff2e290ee612fc98.png 480w, https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-01-download_hu_f7afc82e9f10b9c7.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;383&#34;
		data-flex-basis=&#34;919px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;.zip&lt;/code&gt; file contains a series of folders, one for each service. The defaults seem to be:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;Mail&lt;/dt&gt;
&lt;dd&gt;A unix &lt;code&gt;mbox&lt;/code&gt; file&lt;/dd&gt;
&lt;dt&gt;Calendar&lt;/dt&gt;
&lt;dd&gt;One iCal file for each calendar&lt;/dd&gt;
&lt;dt&gt;Contacts&lt;/dt&gt;
&lt;dd&gt;One vCard file for each group.&lt;/dd&gt;
&lt;dt&gt;Drive&lt;/dt&gt;
&lt;dd&gt;Exports as PDF, docx, xlsx&lt;/dd&gt;
&lt;/dl&gt;
&lt;h2 id=&#34;option-2-export-data-from-each-service&#34;&gt;Option 2: Export data from each service
&lt;/h2&gt;&lt;p&gt;Sometimes, Google Takeout isn&amp;rsquo;t an option.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-01-google-takeout-disabled.png&#34;
	width=&#34;779&#34;
	height=&#34;238&#34;
	srcset=&#34;https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-01-google-takeout-disabled_hu_82821306d6fd1ea8.png 480w, https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-01-google-takeout-disabled_hu_d9ff96b63e087d9b.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;327&#34;
		data-flex-basis=&#34;785px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Mst Google services have some sort of data connection for apps to use, which can be used for export. This means if you have a new contact manager, or want to include your Google Drive in your PC backup, then there are still some options to do so.&lt;/p&gt;
&lt;p&gt;The export formats in these examples should match the Google Takeout defaults. I&amp;rsquo;ve written up a brief guide below for each of the following services:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mail&lt;/li&gt;
&lt;li&gt;Contacts&lt;/li&gt;
&lt;li&gt;Calendar&lt;/li&gt;
&lt;li&gt;Drive&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;mail&#34;&gt;Mail
&lt;/h3&gt;&lt;p&gt;If you are not a power user, then a good option would be to set up a copy of &lt;a class=&#34;link&#34; href=&#34;https://www.mozilla.org/en-US/thunderbird/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Mozilla Thunderbird&lt;/a&gt; to use &lt;a class=&#34;link&#34; href=&#34;https://support.google.com/mail/troubleshooter/1668960?hl=en&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;IMAP&lt;/a&gt;, and regularly using it for your email. This is a simple way to keep a clone of your inbox on your desktop computer, so that it can be included in backups.&lt;/p&gt;
&lt;p&gt;If you are more tech-savvy, then the rest of this section will focus on helping you generate an &lt;code&gt;mbox&lt;/code&gt; file containing a full backup of your email, the same format as Takeout uses. The best tool for that is a Linux program called &lt;a class=&#34;link&#34; href=&#34;http://pyropus.ca/software/getmail/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;getmail&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On Debian or Ubuntu Linux, issue this command to install getmail:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install getmail4
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For other package managers, see &lt;a class=&#34;link&#34; href=&#34;https://github.com/linode/docs/blob/master/docs/email/clients/retrieving-email-using-getmail.md#installing-getmail&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;these directions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First, you need to enable IMAP for your account, see Google&amp;rsquo;s article: &lt;a class=&#34;link&#34; href=&#34;https://support.google.com/mail/troubleshooter/1668960?hl=en&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Get started with IMAP and POP3&lt;/a&gt;, for the steps.&lt;/p&gt;
&lt;p&gt;Now create a file at &lt;code&gt;~/.getmail/getmailrc&lt;/code&gt;, and configure it to read your email account via IMAP/SSL.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;[retriever]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SimpleIMAPSSLRetriever&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;imap.gmail.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;port&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;993&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;username&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;bob@mail.example.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;password&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;....&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;[destination]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;Mboxrd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;path&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;~/inbox&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;[options]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;verbose&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;getmail
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After some time, you will end up with a large &lt;code&gt;mbox&lt;/code&gt; file at &lt;code&gt;~/inbox&lt;/code&gt;, containing all of your mail.&lt;/p&gt;
&lt;p&gt;If, for some reason, you need to use POP3 instead, then see &lt;a class=&#34;link&#34; href=&#34;https://www.mattcutts.com/blog/backup-gmail-in-linux-with-getmail/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this article on Gmail backup&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;contacts&#34;&gt;Contacts
&lt;/h3&gt;&lt;p&gt;Go to your contacts, and find a group. Check the box next to each name, and then find the Export button:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-contacts-export.png&#34;
	width=&#34;386&#34;
	height=&#34;215&#34;
	srcset=&#34;https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-contacts-export_hu_36affdcc75001f40.png 480w, https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-contacts-export_hu_13d3dcdf6816a9f8.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;179&#34;
		data-flex-basis=&#34;430px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Select the vCard format here, as it&amp;rsquo;s the same format which Takeout would have used:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-contacts-export-group-vcard.png&#34;
	width=&#34;564&#34;
	height=&#34;352&#34;
	srcset=&#34;https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-contacts-export-group-vcard_hu_6a1df3a2c50157ee.png 480w, https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-contacts-export-group-vcard_hu_7da28a57657325ca.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;160&#34;
		data-flex-basis=&#34;384px&#34;
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;calendar&#34;&gt;Calendar
&lt;/h3&gt;&lt;p&gt;Google provides a share-able iCal link, which you can download once, but it is only available if your calendar is public.&lt;/p&gt;
&lt;p&gt;So, if your calendar isn&amp;rsquo;t &lt;em&gt;too&lt;/em&gt; sensitive, click &amp;ldquo;Share&amp;rdquo; and make the calendar public:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-calendar-01-share.png&#34;
	width=&#34;470&#34;
	height=&#34;197&#34;
	srcset=&#34;https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-calendar-01-share_hu_977a75f339263e3e.png 480w, https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-calendar-01-share_hu_cef223791a7439dd.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;238&#34;
		data-flex-basis=&#34;572px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-calendar-02-public.png&#34;
	width=&#34;382&#34;
	height=&#34;173&#34;
	srcset=&#34;https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-calendar-02-public_hu_f9c0fb9b2c1559af.png 480w, https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-calendar-02-public_hu_f12ce56167a34246.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;220&#34;
		data-flex-basis=&#34;529px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Go to &amp;ldquo;Calendar Settings&amp;rdquo;, find the iCal link. It may take a few minutes for the link to start working, but once it does, download it, and then turn off public sharing.&lt;/p&gt;
&lt;p&gt;There is a chance that somebody else loads your calendar while its public. An alternative which avoids making the calendar public would be to save the events individually instead.&lt;/p&gt;
&lt;h3 id=&#34;drive&#34;&gt;Drive
&lt;/h3&gt;&lt;p&gt;Exporting from Google Drive is nice and simple. Select all of your files (Shift+Click):&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-drive-select.png&#34;
	width=&#34;448&#34;
	height=&#34;346&#34;
	srcset=&#34;https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-drive-select_hu_e109b21210281a9a.png 480w, https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-drive-select_hu_8315ae04116f270c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;129&#34;
		data-flex-basis=&#34;310px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;And then find the Download button:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-drive-download.png&#34;
	width=&#34;364&#34;
	height=&#34;268&#34;
	srcset=&#34;https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-drive-download_hu_3f01b2a334a42ba6.png 480w, https://mike42.me/blog/2015-02-two-ways-to-back-up-your-google-apps-account/2015-02-drive-download_hu_74d87e6e4875d19c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;135&#34;
		data-flex-basis=&#34;325px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;If you apply this to your whole drive, it may take a while, so you may wish to download it in parts if your Internet can be unreliable.&lt;/p&gt;
&lt;h2 id=&#34;how-do-i-use-these-files&#34;&gt;How do I use these files?
&lt;/h2&gt;&lt;p&gt;Google Drive&amp;rsquo;s files are exported in familiar formats. If you haven&amp;rsquo;t used an &lt;code&gt;mbox&lt;/code&gt;, &lt;code&gt;vCard&lt;/code&gt; or &lt;code&gt;ics&lt;/code&gt; file before, then you will need to find a program which can read these for you.&lt;/p&gt;
&lt;p&gt;Google&amp;rsquo;s support answer &amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;https://support.google.com/accounts/answer/3024195?hl=en&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Download your data: Per-service information&lt;/a&gt;&amp;rdquo; contains a list of files types which you&amp;rsquo;ll run into during this process, and suggests programs which can import them.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to merge edges in GraphViz</title>
        <link>https://mike42.me/blog/2015-02-how-to-merge-edges-in-graphviz</link>
        <pubDate>Sun, 01 Feb 2015 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2015-02-how-to-merge-edges-in-graphviz</guid>
        <description>&lt;p&gt;If you are sketching out a node in graphviz which has many ancestors, a dense collection of arrow-heads can become unsightly:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-02-how-to-merge-edges-in-graphviz/example1.png&#34;
	width=&#34;275&#34;
	height=&#34;251&#34;
	srcset=&#34;https://mike42.me/blog/2015-02-how-to-merge-edges-in-graphviz/example1_hu_957661b2246b84d1.png 480w, https://mike42.me/blog/2015-02-how-to-merge-edges-in-graphviz/example1_hu_fa623a5f06256081.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Example 1 - Edges not merged&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;109&#34;
		data-flex-basis=&#34;262px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The code for the above graph is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;digraph G {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	{a, b, c} -&amp;gt; d;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	d -&amp;gt; e;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To merge the edges together, we can instead point these three nodes to an intermediate node, using edges without arrow. This example is adapted from the GraphViz FAQ (&lt;a class=&#34;link&#34; href=&#34;http://www.graphviz.org/content/FaqMerge&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;link&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;This gives us:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-02-how-to-merge-edges-in-graphviz/example2.png&#34;
	width=&#34;275&#34;
	height=&#34;300&#34;
	srcset=&#34;https://mike42.me/blog/2015-02-how-to-merge-edges-in-graphviz/example2_hu_9e68f211964c091.png 480w, https://mike42.me/blog/2015-02-how-to-merge-edges-in-graphviz/example2_hu_a8379a825b3c6fb9.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Example 2 - edges merged&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;91&#34;
		data-flex-basis=&#34;220px&#34;
	
&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;digraph G {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	d1 [shape=point,width=0.01,height=0.01];
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	{a, b, c} -&amp;gt; d1 [dir=none];
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	d1 -&amp;gt; d;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	d -&amp;gt; e;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To compile these examples, you can use an online tool such as &lt;a class=&#34;link&#34; href=&#34;http://www.webgraphviz.com/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Webgraphviz&lt;/a&gt;. If you have GraphViz installed, then run &lt;code&gt;dot&lt;/code&gt; over them instead:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dot -Tpdf example.dot &amp;gt; example.pdf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>Howto: Tethered photo capture on Linux</title>
        <link>https://mike42.me/blog/2015-01-howto-tethered-photo-capture-on-linux</link>
        <pubDate>Thu, 15 Jan 2015 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2015-01-howto-tethered-photo-capture-on-linux</guid>
        <description>&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-01-howto-tethered-photo-capture-on-linux/2015-01-tethered-capture.png&#34;
	width=&#34;387&#34;
	height=&#34;103&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-howto-tethered-photo-capture-on-linux/2015-01-tethered-capture_hu_fdbbf34dd760457f.png 480w, https://mike42.me/blog/2015-01-howto-tethered-photo-capture-on-linux/2015-01-tethered-capture_hu_6abdd2f88d556d45.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;375&#34;
		data-flex-basis=&#34;901px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Have you ever wondered how professionals get photos to pop up on their computer as they snap them? Most higher-end cameras have mini USB connection, and software is available to retrieve images as they are taken.&lt;/p&gt;
&lt;p&gt;Rather than use a GUI app, in this post I&amp;rsquo;ll use a command-line program called &lt;code&gt;gphoto2&lt;/code&gt; to drop the images into a folder. With large thumbnails set in your file browser, a desktop program would be redundant.&lt;/p&gt;
&lt;h2 id=&#34;basic-process&#34;&gt;Basic process
&lt;/h2&gt;&lt;p&gt;First, you need to install the &lt;code&gt;gphoto2&lt;/code&gt; program. Depending on your system, one of the following commands should do the trick:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install gphoto2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;yum install gphoto2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, plug in the camera. The command to do a &amp;ldquo;tethered capture&amp;rdquo; is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gphoto2 --capture-tethered
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Unfortunately, in most desktop environments, your file manager will mount the camera automatically. If this is the case, then the command will give you an error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mike@mikebox:~$ gphoto2 --capture-tethered
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Waiting for events from camera. Press Ctrl-C to abort.                         
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;*** Error ***              
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;An error occurred in the io-library (&amp;#39;Could not claim the USB device&amp;#39;): Could not claim interface 0 (Device or resource busy). Make sure no other program (gvfs-gphoto2-volume-monitor) or kernel module (such as sdc2xx, stv680, spca50x) is using the device and you have read/write access to the device.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;*** Error (-53: &amp;#39;Could not claim the USB device&amp;#39;) ***       
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;For debugging messages, please use the --debug option.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Debugging messages may help finding a solution to your problem.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;If you intend to send any error or debug messages to the gphoto
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;developer mailing list &amp;lt;gphoto-devel@lists.sourceforge.net&amp;gt;, please run
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gphoto2 as follows:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    env LANG=C gphoto2 --debug --debug-logfile=my-logfile.txt --capture-tethered
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Please make sure there is sufficient quoting around the arguments.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Simply find the camera and unmount it using the eject button:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-01-howto-tethered-photo-capture-on-linux/Screenshot-from-2014-12-24-114052.png&#34;
	width=&#34;253&#34;
	height=&#34;93&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-howto-tethered-photo-capture-on-linux/Screenshot-from-2014-12-24-114052_hu_4d11d298e0c9e50b.png 480w, https://mike42.me/blog/2015-01-howto-tethered-photo-capture-on-linux/Screenshot-from-2014-12-24-114052_hu_a50114589b758963.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;272&#34;
		data-flex-basis=&#34;652px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Now when you type the command, it will block until a photo is taken, and then show you the name of the photo:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;mike&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mikebox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;~$&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;gphoto2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;capture&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tethered&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Waiting&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;events&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;camera&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Press&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Ctrl&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;C&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;abort&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;                         
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;UNKNOWN&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PTP&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Property&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5007&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;changed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Downloading&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;DSC_0236.JPG&amp;#39;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;folder&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/store_00010001/DCIM/100NCD90&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Saving&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;DSC_0236&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;JPG&lt;/span&gt;                                                    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Deleting&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;DSC_0236.JPG&amp;#39;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;folder&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/store_00010001/DCIM/100NCD90&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Each of the photos is loaded into the working directory after you release the shutter, so you simply close &lt;code&gt;gphoto2&lt;/code&gt; when you&amp;rsquo;re done — no manual downloading or SD card required.&lt;/p&gt;
&lt;h2 id=&#34;extending-this-method&#34;&gt;Extending this method
&lt;/h2&gt;&lt;p&gt;Ok, so now that I&amp;rsquo;ve covered this basic use case, the real reason I suggest &lt;code&gt;gphoto2&lt;/code&gt; is that it will let you script just about anything to do with your camera.&lt;/p&gt;
&lt;p&gt;Just typing &lt;code&gt;gphoto2 --help&lt;/code&gt; shows that it can let you trigger a photo or video on a timer, download and delete folders from the camera, or hook up programs via a pipe for processing the files in realtime.&lt;/p&gt;
&lt;p&gt;Endless possibilities.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Locking down your VOIP setup with a SIP Threat Manager</title>
        <link>https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager</link>
        <pubDate>Thu, 08 Jan 2015 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager</guid>
        <description>&lt;p&gt;If you run a Voice over IP network which is available from the Internet, then it&amp;rsquo;s quite important to lock it down properly, so that it isn&amp;rsquo;t hijacked for relaying spam calls at your expense.&lt;/p&gt;
&lt;p&gt;This article will cover the steps you need to deploy the SIP Threat Manager from Allo, which you can think of as a security-focused SIP proxy &amp;amp; firewall.&lt;/p&gt;
&lt;h2 id=&#34;topology&#34;&gt;Topology
&lt;/h2&gt;&lt;p&gt;For example, you might have SIP clients both on-site with your server, and also allow people with their own devices to connect directly from home. One of the simplest ways to harden this setup is to add a specialised SIP router between your server and the Internet, to filter connections and log security-relevant events:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-network2.png&#34;
	width=&#34;561&#34;
	height=&#34;327&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-network2_hu_31f43ca7783f5106.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-network2_hu_b1044e36adab814d.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;VOIP network with STM&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;171&#34;
		data-flex-basis=&#34;411px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This post will show you how to migrate your VOIP network to this potentially more secure topology using Allo&amp;rsquo;s SIP Threat Manager.&lt;/p&gt;
&lt;h2 id=&#34;the-allo-stm-box&#34;&gt;The Allo STM Box
&lt;/h2&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2014-01-stm-front.jpg&#34;
	width=&#34;1024&#34;
	height=&#34;720&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2014-01-stm-front_hu_42e63e83915fe7ce.jpg 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2014-01-stm-front_hu_8601174e3de2d489.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;142&#34;
		data-flex-basis=&#34;341px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2014-01-stm-back.jpg&#34;
	width=&#34;1024&#34;
	height=&#34;720&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2014-01-stm-back_hu_a35ff582495a6b1e.jpg 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2014-01-stm-back_hu_384963d32d6577d1.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;142&#34;
		data-flex-basis=&#34;341px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The STM itself is only small box, with two 100 Mbit/s Ethernet ports, and two USB ports. It is USB-powered, so one of these ports is for powering the box, and the other is for connecting external storage for log files. It is not power-hungry, and I was able to run it from a laptop USB port without any issues. Other than this, it&amp;rsquo;s externally a typical embedded network device: it has indicator lights, a power switch, a factory reset button, and a console port.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2014-01-stm-internal.jpg&#34;
	width=&#34;1023&#34;
	height=&#34;720&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2014-01-stm-internal_hu_9195e7ff0283732c.jpg 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2014-01-stm-internal_hu_2d63d8c693facea4.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;142&#34;
		data-flex-basis=&#34;341px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Internally, it runs a MIPS processor, which appears to host &lt;a class=&#34;link&#34; href=&#34;https://www.snort.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Snort&lt;/a&gt; on embedded Linux.&lt;/p&gt;
&lt;h2 id=&#34;initial-setup&#34;&gt;Initial Setup
&lt;/h2&gt;&lt;p&gt;Although the box advertises that it will work out-of-the-box, I found that it was easier to configure the box to match my network, than to re-work my network around the box. This section will simply show you how to get logged in and change the box&amp;rsquo;s IP address.&lt;/p&gt;
&lt;p&gt;First up, I took a look at the console, which is accessible at a baudrate of 38400. It&amp;rsquo;s far from the most functional CLI around, so I only made use of the &lt;code&gt;factoryreset&lt;/code&gt; function to get a clean slate. It showed a few of the open source packages running, such the dropbear sshd, lighttpd and crond among other familiar programs:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Please press Enter to activate this console. 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Starting pid 942, console /dev/ttyS2: &amp;#39;/usr/bin/maincli&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Shield STM Appliance Appliance
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;shield&amp;gt; factoryreset
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Will output 1024 bit rsa secret key to &amp;#39;/etc/dropbear/dropbear_rsa_host_key&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Generating key, this may take a while...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Public key portion is:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgwCKBcVlWK+UiiELbg2CNfOt9rNmj51dmyz7d10MgRfAk9XU9x+kmlMueCFEBMTchsaywigLw0yFqeMZ
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Fingerprint: md5 50:5b:c2:64:d4:87:f8:86:ab:c6:e1:59:e4:16:c2:cf
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Generating a 1024 bit RSA private key
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...++++++
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...................++++++
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;writing new private key to &amp;#39;/etc/lighttpd/webserver.pem&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-----
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ip: RTNETLINK answers: No such process
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Jan  1 00:40:41 crond[875]: crond 2.3.2 dillon, started, log level 8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mount: mounting /dev/sda1 on /cf/disk failed
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The CLI command &lt;code&gt;show ip&lt;/code&gt; confirmed that the default IP of the box is &lt;code&gt;192.168.100.1&lt;/code&gt;, netmask &lt;code&gt;255.255.255.0&lt;/code&gt;. From a Linux laptop, you can change IP to something nearby and confirm that you can see the device with these commands:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# ifconfig wlan0 192.168.100.2 netmask 255.255.255.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# arp-scan -l&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Interface&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wlan0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;datalink&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;EN10MB&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Ethernet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Starting&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arp&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;scan&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;1.8&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;256&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hosts&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;www&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nta&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;monitor&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;com&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tools&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;arp&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;scan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;mf&#34;&gt;192.168&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;100.1&lt;/span&gt;	&lt;span class=&#34;mi&#34;&gt;00&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;17&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f7&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;00&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;	&lt;span class=&#34;n&#34;&gt;CEM&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Solutions&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Pvt&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Ltd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The STM is then accessible via the web address &lt;code&gt;https://192.168.100.1&lt;/code&gt;, with the default credentials &lt;code&gt;admin&lt;/code&gt; / &lt;code&gt;admin&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen22.png&#34;
	width=&#34;811&#34;
	height=&#34;604&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen22_hu_7b65aef32c9021dc.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen22_hu_926fd1b82b4d0b75.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;134&#34;
		data-flex-basis=&#34;322px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The IP setup is located under &lt;b&gt;Device → General Setup&lt;/b&gt;. Change this to DHCP or a spare address on your network:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen23.png&#34;
	width=&#34;1221&#34;
	height=&#34;626&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen23_hu_2dea0158d402ea1b.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen23_hu_55e86154856002c1.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;195&#34;
		data-flex-basis=&#34;468px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;configuration&#34;&gt;Configuration
&lt;/h2&gt;&lt;p&gt;Now that you can access the STM from any device, your first task is to change the admin password. The button for this is in the top-right:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen21.png&#34;
	width=&#34;174&#34;
	height=&#34;120&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen21_hu_d2972cfc387add63.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen21_hu_f52c6a85aef06672.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;145&#34;
		data-flex-basis=&#34;348px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The STM only allows one session at a time- whilst it&amp;rsquo;s a good idea not to log in twice, this was a surprising limitation. At the STM does not act as its own SIP endpoint, my server was already able to contact the Internet through it at this point.&lt;/p&gt;
&lt;p&gt;I quickly screen captured the available settings so that you can click through them. Some of these are SIP-specific, and others of which are general firewall features. One of the more interesting features which you can&amp;rsquo;t set up with &lt;code&gt;iptables&lt;/code&gt; is location-based IP filtering. This could, for example, block problematic SIP calls coming from fraud hotspots in areas where your organisation doesn&amp;rsquo;t operate.&lt;/p&gt;



&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2015-01-stm-screenshots&#34;
      id=&#34;tabs-post-2015-01-stm-screenshots-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2015-01-stm-screenshots-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Device
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen02.png&#34;
	width=&#34;1386&#34;
	height=&#34;765&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen02_hu_248250cf56f1cae4.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen02_hu_e12253f00e8f0889.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;181&#34;
		data-flex-basis=&#34;434px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen03.png&#34;
	width=&#34;1386&#34;
	height=&#34;765&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen03_hu_3ae4647bb55b48cf.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen03_hu_3bee1b9176ed2ca3.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;181&#34;
		data-flex-basis=&#34;434px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen04.png&#34;
	width=&#34;1386&#34;
	height=&#34;765&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen04_hu_c9ef5322595bad5d.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen04_hu_8f27a365e6327612.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;181&#34;
		data-flex-basis=&#34;434px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2015-01-stm-screenshots&#34;
      id=&#34;tabs-post-2015-01-stm-screenshots-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2015-01-stm-screenshots-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Security Settings
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen05.png&#34;
	width=&#34;1386&#34;
	height=&#34;765&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen05_hu_48865f67cc1b9ca4.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen05_hu_6fb96865e0e52433.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;181&#34;
		data-flex-basis=&#34;434px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen06.png&#34;
	width=&#34;1386&#34;
	height=&#34;765&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen06_hu_3eecc7821aa49721.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen06_hu_a967dadee34cc9b3.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;181&#34;
		data-flex-basis=&#34;434px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen07.png&#34;
	width=&#34;1386&#34;
	height=&#34;765&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen07_hu_198b7eb79ed88541.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen07_hu_6229f224b01f391f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;181&#34;
		data-flex-basis=&#34;434px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen08.png&#34;
	width=&#34;1386&#34;
	height=&#34;765&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen08_hu_db1f96e5fadd4866.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen08_hu_d08f4fc814e24532.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;181&#34;
		data-flex-basis=&#34;434px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen09.png&#34;
	width=&#34;1386&#34;
	height=&#34;765&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen09_hu_eb98fbd77af0d732.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen09_hu_98bb6889e3fe735a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;181&#34;
		data-flex-basis=&#34;434px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen10.png&#34;
	width=&#34;1386&#34;
	height=&#34;765&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen10_hu_253f14d35daa3eee.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen10_hu_58db8c16bff0fe8.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;181&#34;
		data-flex-basis=&#34;434px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen11.png&#34;
	width=&#34;1386&#34;
	height=&#34;765&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen11_hu_c1f0bf063db5fe69.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen11_hu_a63af8f300b42e69.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;181&#34;
		data-flex-basis=&#34;434px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen12.png&#34;
	width=&#34;1386&#34;
	height=&#34;765&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen12_hu_ed5ffc8a0a041287.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen12_hu_6b427cdc58d07c00.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;181&#34;
		data-flex-basis=&#34;434px&#34;
	
&gt;&lt;/p&gt;
&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2015-01-stm-screenshots&#34;
      id=&#34;tabs-post-2015-01-stm-screenshots-2&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2015-01-stm-screenshots-2&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Security Alerts
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen13.png&#34;
	width=&#34;1386&#34;
	height=&#34;765&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen13_hu_29c7ded14c9ce4d0.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen13_hu_679eb852fa0b1658.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;181&#34;
		data-flex-basis=&#34;434px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2015-01-stm-screenshots&#34;
      id=&#34;tabs-post-2015-01-stm-screenshots-3&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2015-01-stm-screenshots-3&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Tools
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen14.png&#34;
	width=&#34;1386&#34;
	height=&#34;765&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen14_hu_f7cd60c08b50ba89.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen14_hu_340f331b547a0450.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;181&#34;
		data-flex-basis=&#34;434px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen15.png&#34;
	width=&#34;1386&#34;
	height=&#34;765&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen15_hu_25055c71bf9f11da.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen15_hu_7e5b339cac4ef634.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;181&#34;
		data-flex-basis=&#34;434px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen16.png&#34;
	width=&#34;1386&#34;
	height=&#34;765&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen16_hu_a920204e97cc9fcb.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen16_hu_70747631a100c248.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;181&#34;
		data-flex-basis=&#34;434px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen17.png&#34;
	width=&#34;1386&#34;
	height=&#34;765&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen17_hu_91fda237e8e942c.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen17_hu_a5095e70955919cf.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;181&#34;
		data-flex-basis=&#34;434px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen18.png&#34;
	width=&#34;1386&#34;
	height=&#34;765&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen18_hu_ee8bb90715609a4e.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen18_hu_fc9e6c51031d901e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;181&#34;
		data-flex-basis=&#34;434px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen19.png&#34;
	width=&#34;1386&#34;
	height=&#34;765&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen19_hu_45f9e0dbeef16911.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen19_hu_14e7f9ec4719f634.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;181&#34;
		data-flex-basis=&#34;434px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen20.png&#34;
	width=&#34;1386&#34;
	height=&#34;765&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen20_hu_baf2a0a4a55a07c1.png 480w, https://mike42.me/blog/2015-01-locking-down-your-voip-setup-with-a-sip-threat-manager/2015-01-stm-screen20_hu_72a9a48fe616472e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;181&#34;
		data-flex-basis=&#34;434px&#34;
	
&gt;&lt;/p&gt;
&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;So once the network is set up on the STM, no changes need to be applied to your SIP server, other than its gateway or IP.&lt;/p&gt;
&lt;h2 id=&#34;notes&#34;&gt;Notes
&lt;/h2&gt;&lt;p&gt;Whilst this box works as it&amp;rsquo;s supposed to, I found it to have an un-polished user experience.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The network interface labels on the box had a label over them with the opposite information.&lt;/li&gt;
&lt;li&gt;The box is closed on port 80: It doesn&amp;rsquo;t reply to HTTP requests, even to redirect them to HTTPS.&lt;/li&gt;
&lt;li&gt;The command prompt wasn&amp;rsquo;t as useful as other network devices.&lt;/li&gt;
&lt;li&gt;I couldn&amp;rsquo;t get SSH login or NTP to work, although I didn&amp;rsquo;t investigate these in great detail.&lt;/li&gt;
&lt;li&gt;The LAN interface (but not the WAN interface) did not light up when connected to a Gigabit POE network, but did work on a 100 megabit network.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, there are some positives: The 100 Mbit/s interfaces are more than sufficient for voice traffic, the configuration was simple, and USB is a good choice of power supply for equipment which can be connected directly to a server.&lt;/p&gt;
&lt;h2 id=&#34;do-you-really-need-another-box&#34;&gt;Do you really need another box?
&lt;/h2&gt;&lt;p&gt;This depends on your setup. If your VOIP server doesn&amp;rsquo;t speak to the Internet, then this box won&amp;rsquo;t fit into your topology.&lt;/p&gt;
&lt;p&gt;If it only sees the outside world via an ISP-run SIP trunk, then this type of security is probably not necessary either. Security measures you would use instead are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use firewall rules to restrict connections so that only the SIP trunk can speak to your VOIP server.&lt;/li&gt;
&lt;li&gt;Configure your VOIP server to &amp;ldquo;stay on the line&amp;rdquo; for calls (&lt;code&gt;directmedia=no&lt;/code&gt; in Asterisk) so that the phones do not speak directly to the trunk, and disallow registration from the Internet.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your VOIP server accepts connections from the public internet throgh SIP, then some sort of separate, SIP-aware firewall or proxy is highly advisable.&lt;/p&gt;
&lt;h2 id=&#34;acknowledgement&#34;&gt;Acknowledgement
&lt;/h2&gt;&lt;p&gt;Thanks to Allo (allo.com) for sending in the box which is used for this example setup.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to set up Asterisk in 10 minutes</title>
        <link>https://mike42.me/blog/2015-01-how-to-set-up-asterisk-in-10-minutes</link>
        <pubDate>Fri, 02 Jan 2015 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2015-01-how-to-set-up-asterisk-in-10-minutes</guid>
        <description>&lt;p&gt;Asterisk is an open-source IP PABX, meaning it lets you run a phone system over your computer network. Whilst IP telephony has been gaining the upper hand over traditional PABX&amp;rsquo;s for years, few people outside the industry realise just how easy it is to set up your own phone server.&lt;/p&gt;
&lt;p&gt;With this guide, you can turn any Linux device into your own PABX for free. We&amp;rsquo;ll set up two SIP devices on a small network, so that they can dial each other.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-01-how-to-set-up-asterisk-in-10-minutes/2014-12-asterisk-example-diagram.png&#34;
	width=&#34;344&#34;
	height=&#34;155&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-how-to-set-up-asterisk-in-10-minutes/2014-12-asterisk-example-diagram_hu_349e6ba28a61d502.png 480w, https://mike42.me/blog/2015-01-how-to-set-up-asterisk-in-10-minutes/2014-12-asterisk-example-diagram_hu_da35c3df680db366.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;221&#34;
		data-flex-basis=&#34;532px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;prepare-the-environment&#34;&gt;Prepare the environment
&lt;/h2&gt;&lt;p&gt;First, you should get something with Linux. A virtual machine, a spare laptop, a Raspberry pi- anything.&lt;/p&gt;
&lt;p&gt;Install asterisk with one of the following commands, depending on your distribution:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install asterisk
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;yum install asterisk
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you don&amp;rsquo;t have an IP phone handy, then you need a program on your computer which speaks SIP (Session Initiation Protocol). This guide uses &lt;a class=&#34;link&#34; href=&#34;http://www.linphone.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Linphone&lt;/a&gt; (available for Linux and Windows among other platforms) and the Polycom 331 as examples, but any two SIP endpoints will work just as well for testing.&lt;/p&gt;
&lt;h2 id=&#34;make-users-on-the-server&#34;&gt;Make users on the server
&lt;/h2&gt;&lt;p&gt;Asterisk keeps its configuration in &lt;code&gt;/etc/asterisk&lt;/code&gt;. The file we need to edit for this setup is &lt;code&gt;users.conf&lt;/code&gt;. Open it up with your favourite text editor:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nano /etc/asterisk/users.conf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The syntax is similar to &lt;code&gt;.ini&lt;/code&gt; files. Add two users to the bottom of the file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;[6001]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;fullname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;Example Bob&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;secret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;1234&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;hassip&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;yes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;context&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;users&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;host&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;dynamic&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;[6002]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;fullname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;Example Joe&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;secret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;1234&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;hassip&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;yes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;context&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;users&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;host&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;dynamic&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What does this mean?&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;code&gt;[600..]&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;This is the username, and will become the user&amp;rsquo;s &lt;em&gt;extension&lt;/em&gt; on our small network. Dial 6001 for Bob or 6002 for Joe. Whilst &lt;code&gt;&#39;bob&#39;&lt;/code&gt; and &lt;code&gt;&#39;joe&#39;&lt;/code&gt; could also be used here, numeric usernames are more common.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;fullname = ...&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;Used in the Caller ID.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;secret = ...&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;The password used to log in. In a secure system, you would use something other than &lt;code&gt;1234&lt;/code&gt;!&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;hassip = yes&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;This tells Asterisk to make a SIP account for the user. Asterisk supports a few other account types, but SIP is the most widely implemented.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;context = users&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;A context is a bit like a &lt;em&gt;category&lt;/em&gt; for the user. The extensions which they can dial depend on this.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;host = dynamic&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;This tells Asterisk that the users &lt;em&gt;don&amp;rsquo;t have a fixed IP address&lt;/em&gt;. This means that they must register periodically with the SIP server so that their IP is known.&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;To activate these changes, save the file, and &lt;code&gt;reload&lt;/code&gt; the configuration through the Asterisk console:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;mike&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# asterisk -r -vvvvvvvvv&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;CLI&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;reload&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;CLI&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sip&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;show&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;users&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Username&lt;/span&gt;                   &lt;span class=&#34;n&#34;&gt;Secret&lt;/span&gt;           &lt;span class=&#34;n&#34;&gt;Accountcode&lt;/span&gt;      &lt;span class=&#34;n&#34;&gt;Def&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Context&lt;/span&gt;      &lt;span class=&#34;n&#34;&gt;ACL&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;ForcerPort&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;mi&#34;&gt;6002&lt;/span&gt;                       &lt;span class=&#34;mi&#34;&gt;1234&lt;/span&gt;                              &lt;span class=&#34;n&#34;&gt;users&lt;/span&gt;            &lt;span class=&#34;n&#34;&gt;No&lt;/span&gt;   &lt;span class=&#34;n&#34;&gt;Yes&lt;/span&gt;       
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;mi&#34;&gt;6001&lt;/span&gt;                       &lt;span class=&#34;mi&#34;&gt;1234&lt;/span&gt;                              &lt;span class=&#34;n&#34;&gt;users&lt;/span&gt;            &lt;span class=&#34;n&#34;&gt;No&lt;/span&gt;   &lt;span class=&#34;n&#34;&gt;Yes&lt;/span&gt;       
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;All of those &lt;em&gt;v&lt;/em&gt;&amp;rsquo;s stand for &lt;strong&gt;verbose&lt;/strong&gt;, meaning that the asterisk console will give you more information.&lt;/p&gt;
&lt;h2 id=&#34;configure-the-clients&#34;&gt;Configure the clients
&lt;/h2&gt;&lt;p&gt;First you should find out your server&amp;rsquo;s IP address. From the terminal, you can find this with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ifconfig
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Setting up &amp;ldquo;Example Joe&amp;rdquo; on a Linphone instance only takes a few clicks. Add a new account, with &lt;code&gt;6002&lt;/code&gt; as the identity, and your asterisk server as the proxy address (eg: &lt;code&gt;sip://voip.example.com&lt;/code&gt;). Click the image below for an example:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-01-how-to-set-up-asterisk-in-10-minutes/2014-12-asterisk-linphone-configuration.png&#34;
	width=&#34;906&#34;
	height=&#34;588&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-how-to-set-up-asterisk-in-10-minutes/2014-12-asterisk-linphone-configuration_hu_67fe5016e5a4e158.png 480w, https://mike42.me/blog/2015-01-how-to-set-up-asterisk-in-10-minutes/2014-12-asterisk-linphone-configuration_hu_bd451817a0c4704.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Linphone account setup&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;154&#34;
		data-flex-basis=&#34;369px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Meanwhile, the Polycom 331 can be configured as &amp;ldquo;Example Bob&amp;rdquo; by navigating the menus on the phone itself, or via the web (suggested). The default login is:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;Username:&lt;/dt&gt;
&lt;dd&gt;Polycom&lt;/dd&gt;
&lt;dt&gt;Password:&lt;/dt&gt;
&lt;dd&gt;456&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-01-how-to-set-up-asterisk-in-10-minutes/2014-12-asterisk-polycom-331-config.png&#34;
	width=&#34;713&#34;
	height=&#34;646&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-how-to-set-up-asterisk-in-10-minutes/2014-12-asterisk-polycom-331-config_hu_326e65da49751375.png 480w, https://mike42.me/blog/2015-01-how-to-set-up-asterisk-in-10-minutes/2014-12-asterisk-polycom-331-config_hu_ef20509914c00269.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;The Polycom 331 web interface.&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;110&#34;
		data-flex-basis=&#34;264px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Your asterisk server address needs to be added under &lt;strong&gt;SIP -&amp;gt; Servers -&amp;gt; Server 1&lt;/strong&gt;, while Example Bob&amp;rsquo;s identity is added under &lt;strong&gt;Lines -&amp;gt; Line1&lt;/strong&gt;. Click the below images for an example.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2015-01-how-to-set-up-asterisk-in-10-minutes/2014-12-asterisk-polycom-331-config-2.png&#34;
	width=&#34;713&#34;
	height=&#34;646&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-how-to-set-up-asterisk-in-10-minutes/2014-12-asterisk-polycom-331-config-2_hu_3368d051e7a70aa8.png 480w, https://mike42.me/blog/2015-01-how-to-set-up-asterisk-in-10-minutes/2014-12-asterisk-polycom-331-config-2_hu_4f68d4767396a416.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Polycom 331Server (SIP) configuration&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;110&#34;
		data-flex-basis=&#34;264px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2015-01-how-to-set-up-asterisk-in-10-minutes/2014-12-asterisk-polycom-331-config-3.png&#34;
	width=&#34;713&#34;
	height=&#34;646&#34;
	srcset=&#34;https://mike42.me/blog/2015-01-how-to-set-up-asterisk-in-10-minutes/2014-12-asterisk-polycom-331-config-3_hu_94eceba27f0cf9ca.png 480w, https://mike42.me/blog/2015-01-how-to-set-up-asterisk-in-10-minutes/2014-12-asterisk-polycom-331-config-3_hu_64aec6709456e51c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Polycom 331 line configuration&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;110&#34;
		data-flex-basis=&#34;264px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Once these are saved, the two clients will register with the server. In SIP, clients periodically register so that the server knows where to find them.&lt;/p&gt;
&lt;p&gt;In the asterisk console, you will see something like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-- Registered SIP &amp;#39;6001&amp;#39; at 192.168.1.4:5060
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &amp;gt; Saved useragent &amp;#34;PolycomSoundPointIP-SPIP_331-UA/3.3.3.0069&amp;#34; for peer 6001
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If registration fails, the console will tell you why, provided that you have set the verbosity high enough&lt;/p&gt;
&lt;p&gt;You can check which users have registered with this command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;CLI&amp;gt; sip show peers
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Name/username              Host                                    Dyn Forcerport ACL Port     Status     
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;6001/6001                  192.168.1.4                              D   N             5060     Unmonitored 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;6002                       (Unspecified)                            D   N             0        Unmonitored 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2 sip peers [Monitored: 0 online, 0 offline Unmonitored: 1 online, 1 offline]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Unfortunately, even after both users have registered, they aren&amp;rsquo;t ready to communicate yet.&lt;/p&gt;
&lt;h2 id=&#34;add-extensions-to-the-server&#34;&gt;Add extensions to the server
&lt;/h2&gt;&lt;p&gt;In the world of VOIP, an extension is not a real loop of copper, but a sequential list of things to do when a number is dialled.&lt;/p&gt;
&lt;p&gt;This extra step is where Asterisk gets its flexibility. With your &lt;code&gt;extensions.conf&lt;/code&gt; setup, you could set your instance to redirect numbers, or dial for 12 seconds before going to voicemail.&lt;/p&gt;
&lt;p&gt;We haven&amp;rsquo;t told the server what to do, so if &amp;ldquo;Example Bob&amp;rdquo; makes a call, it wont work yet:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  == Using SIP RTP CoS mark 5
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[Nov 15 07:59:30] NOTICE[6070]: chan_sip.c:22753 handle_request_invite: Call from &amp;#39;6001&amp;#39; (192.168.1.4:5060) to extension &amp;#39;6002&amp;#39; rejected because extension not found in context &amp;#39;users&amp;#39;.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To add extensions, open &lt;code&gt;extensions.conf&lt;/code&gt; up:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nano /etc/asterisk/extensions.conf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The syntax is still INI-like. Under &lt;code&gt;[users]&lt;/code&gt;, we add the steps for each extension, numbered sequentially. In this case, there is only 1 step for each extension: to dial a SIP user.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[users]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;exten =&amp;gt; 6001,1,Dial(SIP/6001)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;exten =&amp;gt; 6002,1,Dial(SIP/6002)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the Asterisk console, type &lt;code&gt;reload&lt;/code&gt; to activate the changes.&lt;/p&gt;
&lt;p&gt;Now, as planned, both users on the network can dial each-other and have a chat.&lt;/p&gt;
&lt;h2 id=&#34;more-advanced-setups&#34;&gt;More advanced setups
&lt;/h2&gt;&lt;p&gt;Ok, so you&amp;rsquo;ve built what is essentially an intercom, but not a full phone system! For a start, you need a way to dial the outside world, and let the outside world dial you. For that, you&amp;rsquo;ll need to work with hardware and service providers.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>New Wordpress theme</title>
        <link>https://mike42.me/blog/2014-12-new-wordpress-theme</link>
        <pubDate>Tue, 30 Dec 2014 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2014-12-new-wordpress-theme</guid>
        <description>&lt;p&gt;Since the last &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2014-03-successful-migration-to-wordpress-in-3-easy-steps&#34; &gt;major revision&lt;/a&gt; of my site setup, I&amp;rsquo;ve been including more technical content, which would be easier to read with syntax highlighting and tabs.&lt;/p&gt;
&lt;p&gt;The most visible part of the transition is now complete:&lt;/p&gt;



&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-tabs-2014-12-new-wordpress-theme&#34;
      id=&#34;tabs-tabs-2014-12-new-wordpress-theme-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-tabs-2014-12-new-wordpress-theme-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Before
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2014-12-new-wordpress-theme/2014-12-30-skittlish.png&#34;
	width=&#34;1216&#34;
	height=&#34;813&#34;
	srcset=&#34;https://mike42.me/blog/2014-12-new-wordpress-theme/2014-12-30-skittlish_hu_efbcd0e7087110c1.png 480w, https://mike42.me/blog/2014-12-new-wordpress-theme/2014-12-30-skittlish_hu_fbb670e5384b852e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Skittlish theme on mike.bitrevision.com&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;149&#34;
		data-flex-basis=&#34;358px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-tabs-2014-12-new-wordpress-theme&#34;
      id=&#34;tabs-tabs-2014-12-new-wordpress-theme-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-tabs-2014-12-new-wordpress-theme-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      After
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2014-12-new-wordpress-theme/2014-12-30-bootstrap.png&#34;
	width=&#34;1216&#34;
	height=&#34;813&#34;
	srcset=&#34;https://mike42.me/blog/2014-12-new-wordpress-theme/2014-12-30-bootstrap_hu_b86da0c34cf790a1.png 480w, https://mike42.me/blog/2014-12-new-wordpress-theme/2014-12-30-bootstrap_hu_83d0dea7f3ef04fa.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Bootstrap-based theme on mike.bitrevision.com&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;149&#34;
		data-flex-basis=&#34;358px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The old theme was &lt;a class=&#34;link&#34; href=&#34;http://www.pmwiki.org/wiki/Skins/Skittlish&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Skittlish&lt;/a&gt;, but I decided to move to a new theme which was based on Bootstrap, so that I could use its components. The new theme is a modified version of the default &lt;a class=&#34;link&#34; href=&#34;https://wordpress.org/themes/twentyfourteen&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;twentyfourteen&lt;/a&gt; theme, using the visual style of &lt;a class=&#34;link&#34; href=&#34;https://wordpress.org/themes/morphic&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;morphic&lt;/a&gt;, with &lt;a class=&#34;link&#34; href=&#34;http://prismjs.com/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Prism.js&lt;/a&gt; added for code highlighting.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>From SIP to speaker: Setting up a VOIP Zone Controller</title>
        <link>https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller</link>
        <pubDate>Thu, 20 Nov 2014 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller</guid>
        <description>&lt;p&gt;In many scenarios where you find a phone system, you&amp;rsquo;ll also find a PA system. Ideally, we want the audio from the phones to be able to reach the PA system when a special number is dialled:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller/2014-11-cyberdata-zone.png&#34;
	width=&#34;536&#34;
	height=&#34;82&#34;
	srcset=&#34;https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller/2014-11-cyberdata-zone_hu_142935c463441010.png 480w, https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller/2014-11-cyberdata-zone_hu_d8370a2d4eb4af7d.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Ideal VOIP Zone Controller setup&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;653&#34;
		data-flex-basis=&#34;1568px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;With analog phone systems, this is a common feature. IP-based systems can do this too, with the help of a VOIP Zone Controller.&lt;/p&gt;
&lt;p&gt;I think of a Zone Controller as an &amp;ldquo;Ethernet to RCA&amp;rdquo; adapter. This article will show you how to get a CyberData controller set up with Asterisk.&lt;/p&gt;
&lt;h2 id=&#34;the-equipment&#34;&gt;The equipment
&lt;/h2&gt;&lt;p&gt;I settled on this CyberData 4-port Zone Controller, which is quite small, POE-powered, and is of course a reliable and configurable embedded SIP endpoint:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller/2014-11-cyberdata-front.jpg&#34;
	width=&#34;1024&#34;
	height=&#34;478&#34;
	srcset=&#34;https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller/2014-11-cyberdata-front_hu_14e35cc8319325b5.jpg 480w, https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller/2014-11-cyberdata-front_hu_c4ca748c15793d93.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Front view - CyberData 4 port Zone Controller&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;214&#34;
		data-flex-basis=&#34;514px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller/2014-11-cyberdata-back.jpg&#34;
	width=&#34;1024&#34;
	height=&#34;468&#34;
	srcset=&#34;https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller/2014-11-cyberdata-back_hu_5efb503df85024ef.jpg 480w, https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller/2014-11-cyberdata-back_hu_eb0030134bd4d0b6.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Back view - CyberData 4 port Zone Controller&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;218&#34;
		data-flex-basis=&#34;525px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;In a typical configuration, the controller would continually receive audio, such as background music, and then silence it when an announcement is made (this is called &amp;ldquo;night ringer&amp;rdquo;).&lt;/p&gt;
&lt;p&gt;This device has 4 different audio outputs, and waits for a DTMF tone by default, which is then mapped to one or more outputs. I had a very simple use case, and disabled this, so that dialing the box simply caused audio output.&lt;/p&gt;
&lt;h2 id=&#34;on-the-voip-server&#34;&gt;On the VOIP server
&lt;/h2&gt;&lt;p&gt;Hopefully, you&amp;rsquo;re using Asterisk to run your phone network! This is the usual platform for VOIP enthusiasts. If you&amp;rsquo;re dealing with a proprietary system, then you&amp;rsquo;ll need to skip this section.&lt;/p&gt;
&lt;p&gt;First, &lt;code&gt;sip.conf&lt;/code&gt; needs to have an entry for the zone controller. This should look like a regular phone. Without going into the intricacies of Asterisk&amp;rsquo;s SIP configuration, this snippet adds the zone controller as user 1234. It&amp;rsquo;s given the caller ID &amp;ldquo;PA System&amp;rdquo;, and is allowed it to connect from any IP address with the specified secret:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;[1234]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;peer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;host&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;dynamic&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;context&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;users&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;hassip&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;yes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;directmedia&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;no&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;fullname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;PA System&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;callerid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;PA System&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;secret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;... (something random here) ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;nat&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;no&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the &lt;code&gt;extensions.conf&lt;/code&gt;, you can then make the device contactable by all phones by adding a line to the &lt;code&gt;users&lt;/code&gt; context:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;[users]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;exten&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;gt; 1234,1,Dial(SIP/1234)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;setting-up-the-controller&#34;&gt;Setting up the controller
&lt;/h2&gt;&lt;p&gt;First, you need to plug the audio out into some sort of speaker, and the Ethernet into a POE network with an IP phone system.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller/2014-11-cyberdata-running.jpg&#34;
	width=&#34;1024&#34;
	height=&#34;673&#34;
	srcset=&#34;https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller/2014-11-cyberdata-running_hu_af355eb755c8c63c.jpg 480w, https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller/2014-11-cyberdata-running_hu_87f65f2d2cb9f29f.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;In operation - CyberData 4 port Zone Controller&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;152&#34;
		data-flex-basis=&#34;365px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The CyberData devices have a web interface, so you need to find it on the network. I suggest filtering the output of &lt;code&gt;arp-scan -l eth0&lt;/code&gt; on GNU/Linux, which will find the IP address corresponding to the MAC address printed on your device.&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;ve found it, the configuration is dead simple. Type the IP address into a web browser, and log in as user &amp;ldquo;admin&amp;rdquo;, password &amp;ldquo;admin&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller/2014-11-cyberdata-pic01.png&#34;
	width=&#34;1054&#34;
	height=&#34;746&#34;
	srcset=&#34;https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller/2014-11-cyberdata-pic01_hu_b4ac71adc14e51a1.png 480w, https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller/2014-11-cyberdata-pic01_hu_ee9004d9131f627a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Main configuration- CyberData 4 port Zone Controller&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;141&#34;
		data-flex-basis=&#34;339px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The web interface is extensive, and shows the depth of options which are used in this niche application, such as custom audio snippets and test routines.&lt;/p&gt;
&lt;p&gt;Of course, you may want to adjust the network configuration, which is on the &amp;ldquo;Network Configuration&amp;rdquo; page. Once you adjust anything, no changes will take effect until you save and reboot.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller/2014-11-cyberdata-pic03.png&#34;
	width=&#34;1054&#34;
	height=&#34;746&#34;
	srcset=&#34;https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller/2014-11-cyberdata-pic03_hu_d4956654d801fab6.png 480w, https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller/2014-11-cyberdata-pic03_hu_d474fe0cb7ff0487.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;IP configuration panel&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;141&#34;
		data-flex-basis=&#34;339px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Remembering the login and password you set up in &lt;code&gt;sip.conf&lt;/code&gt;, you will need to fill in the SIP configuration as well.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller/2014-11-cyberdata-pic04.png&#34;
	width=&#34;1054&#34;
	height=&#34;746&#34;
	srcset=&#34;https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller/2014-11-cyberdata-pic04_hu_64c7faad2a50990a.png 480w, https://mike42.me/blog/2014-11-from-sip-to-speaker-setting-up-a-voip-zone-controller/2014-11-cyberdata-pic04_hu_be5d9bd8734388b2.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;SIP configuration panel&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;141&#34;
		data-flex-basis=&#34;339px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Once you reboot, you should see the device register from the Asterisk console, and it will then be reachable. More configuration options to explore include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tick &amp;ldquo;Bypass SIP DTMF Entry&amp;rdquo; in &amp;ldquo;Zone Config&amp;rdquo; if you don&amp;rsquo;t have zones.&lt;/li&gt;
&lt;li&gt;Set the admin password (!)&lt;/li&gt;
&lt;li&gt;Take a backup by exporting the configuration from the main page&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>What is ESC/POS, and how do I use it?</title>
        <link>https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it</link>
        <pubDate>Wed, 12 Nov 2014 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it</guid>
        <description>&lt;p&gt;ESC/POS is the command set which makes receipt printers print.&lt;/p&gt;

      &lt;div
          style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
        &lt;iframe
          src=&#34;https://player.vimeo.com/video/110436039?dnt=0&#34;
            style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allow=&#34;fullscreen&#34;&gt;
        &lt;/iframe&gt;
      &lt;/div&gt;

&lt;h2 id=&#34;introduction&#34;&gt;Introduction
&lt;/h2&gt;&lt;p&gt;Before we begin, there&amp;rsquo;s three things you need to know about ESC/POS:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Most modern receipt printers support it in some form.&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s dead simple to write.&lt;/li&gt;
&lt;li&gt;Commands start with an ESC character (ASCII 27).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The most useful reference for the protocol is &lt;a class=&#34;link&#34; href=&#34;https://web.archive.org/web/20200110095204/http://content.epson.de/fileadmin/content/files/RSD/downloads/escpos.pdf&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this Epson FAQ&lt;/a&gt;, which I&amp;rsquo;ve used previously to implement &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;an ESC/POS printer driver for PHP&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Incidentally, the receipt printed in the above video is an example from the &lt;code&gt;escpos-php&lt;/code&gt; repository. I&amp;rsquo;ll step through this print-out, as it demonstrates all of the basic ESC/POS features.&lt;/p&gt;
&lt;h2 id=&#34;command-structure&#34;&gt;Command structure
&lt;/h2&gt;&lt;p&gt;Four specific ASCII characters make appearances in the command sequences-
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Abbreviation&lt;/th&gt;
          &lt;th&gt;Name&lt;/th&gt;
          &lt;th&gt;Code (Hex)&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;NUL&lt;/td&gt;
          &lt;td&gt;Null&lt;/td&gt;
          &lt;td&gt;0x00&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;LF&lt;/td&gt;
          &lt;td&gt;Line Feed&lt;/td&gt;
          &lt;td&gt;0x0A&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;ESC&lt;/td&gt;
          &lt;td&gt;Escape&lt;/td&gt;
          &lt;td&gt;0x1B&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;GS&lt;/td&gt;
          &lt;td&gt;Group Separator&lt;/td&gt;
          &lt;td&gt;0x1D&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Regular text is simply sent to the printer, separated by line-breaks. Commands begin with ESC or GS, and are followed by a printable character, and sometimes some numbers&lt;/p&gt;
&lt;p&gt;Numbers are simply passed as a character. For example, &amp;lsquo;5&amp;rsquo; is passed as 0x05.&lt;/p&gt;
&lt;h2 id=&#34;examples&#34;&gt;Examples
&lt;/h2&gt;&lt;p&gt;These examples are taken from the output of &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php/blob/development/example/demo.php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;demo.php&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;initialisation&#34;&gt;Initialisation
&lt;/h3&gt;&lt;p&gt;When you first connect to the printer, you should initialise it. This reverts to default formatting, rather than the triple-underlined double-strike font which the previous print-out may have been using.&lt;/p&gt;



&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-init&#34;
      id=&#34;tabs-post-2014-11-escpos-init-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-init-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Command
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;dl&gt;
&lt;dt&gt;The command to reset the formatting is:&lt;/dt&gt;
&lt;dd&gt;ESC @&lt;/dd&gt;
&lt;/dl&gt;
&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-init&#34;
      id=&#34;tabs-post-2014-11-escpos-init-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-init-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-init&#34;
      id=&#34;tabs-post-2014-11-escpos-init-2&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-init-2&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Hexdump
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000000  1b 40                                             |.@|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000003
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3 id=&#34;hello-world-text&#34;&gt;&amp;ldquo;Hello world&amp;rdquo; text
&lt;/h3&gt;&lt;p&gt;This is the simplest type of receipt, and contains only unformatted text.&lt;/p&gt;



&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-hello&#34;
      id=&#34;tabs-post-2014-11-hello-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-hello-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-01.png&#34;
	width=&#34;600&#34;
	height=&#34;75&#34;
	srcset=&#34;https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-01_hu_332e049208e60c91.png 480w, https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-01_hu_c19d7dc8f8f473ec.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;800&#34;
		data-flex-basis=&#34;1920px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-hello&#34;
      id=&#34;tabs-post-2014-11-hello-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-hello-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Command
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p&gt;Text is simply sent to the printer.&lt;/p&gt;
&lt;p&gt;Each line must be terminated by a line feed.&lt;/p&gt;
&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-hello&#34;
      id=&#34;tabs-post-2014-11-hello-2&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-hello-2&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Text */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello world&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-hello&#34;
      id=&#34;tabs-post-2014-11-hello-3&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-hello-3&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Hexdump
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000000  1b 40 48 65 6c 6c 6f 20  77 6f 72 6c 64 0a 1d 56  |.@Hello world..V|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000010  41 03                                             |A.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000012
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3 id=&#34;line-feeds&#34;&gt;Line feeds
&lt;/h3&gt;&lt;p&gt;The printer can quickly skip past a given number of lines with this command.&lt;/p&gt;



&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-linefeed&#34;
      id=&#34;tabs-post-2014-11-escpos-linefeed-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-linefeed-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-02.png&#34;
	width=&#34;600&#34;
	height=&#34;405&#34;
	srcset=&#34;https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-02_hu_aeaf6ebd31275e8d.png 480w, https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-02_hu_d5d342da03a0c3d8.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;148&#34;
		data-flex-basis=&#34;355px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-linefeed&#34;
      id=&#34;tabs-post-2014-11-escpos-linefeed-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-linefeed-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Command
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;dl&gt;
&lt;dt&gt;The commands are:&lt;/dt&gt;
&lt;dd&gt;LF&lt;/dd&gt;
&lt;dd&gt;ESC d [ number ]&lt;/dd&gt;
&lt;dd&gt;ESC v [ number ]&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;The first command feeds forward, the second feeds in reverse. From the example, it can be seen that the demo printer does not support reverse paper feeding.&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-linefeed&#34;
      id=&#34;tabs-post-2014-11-escpos-linefeed-2&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-linefeed-2&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require_once&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;dirname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;__FILE__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/escpos-php/Escpos.php&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Escpos&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Line feeds */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ABC&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;DEF&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feedReverse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;GHI&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-linefeed&#34;
      id=&#34;tabs-post-2014-11-escpos-linefeed-3&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-linefeed-3&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Hexdump
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000000  1b 40 41 42 43 1b 64 07  44 45 46 1b 65 03 47 48  |.@ABC.d.DEF.e.GH|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000010  49 0a 1d 56 41 03                                 |I..VA.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000016
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3 id=&#34;print-modes&#34;&gt;Print modes
&lt;/h3&gt;&lt;p&gt;Print modes include font height, width and boldness into a single attribute.&lt;/p&gt;



&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-printmodes&#34;
      id=&#34;tabs-post-2014-11-escpos-printmodes-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-printmodes-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-03.png&#34;
	width=&#34;600&#34;
	height=&#34;2326&#34;
	srcset=&#34;https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-03_hu_d91545a27d56b32e.png 480w, https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-03_hu_adfcba8d62fd613c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;25&#34;
		data-flex-basis=&#34;61px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-printmodes&#34;
      id=&#34;tabs-post-2014-11-escpos-printmodes-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-printmodes-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Command
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;dl&gt;
&lt;dt&gt;The command is:&lt;/dt&gt;
&lt;dd&gt;ESC ! [number]&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;The font modes are made from logically OR&amp;rsquo;ing together a selection of attributes. 0 represents plan Font A text. Mode flags are:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Mode&lt;/th&gt;
          &lt;th&gt;Number&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Font A (no mode)&lt;/td&gt;
          &lt;td&gt;0&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Font B&lt;/td&gt;
          &lt;td&gt;1&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Emphasized&lt;/td&gt;
          &lt;td&gt;8&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Double height&lt;/td&gt;
          &lt;td&gt;16&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Double width&lt;/td&gt;
          &lt;td&gt;32&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Underline&lt;/td&gt;
          &lt;td&gt;128&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The example receipt illustrates the effect of each flag.&lt;/p&gt;
&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-printmodes&#34;
      id=&#34;tabs-post-2014-11-escpos-printmodes-2&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-printmodes-2&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Font modes */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$modes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;MODE_FONT_A&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;MODE_FONT_B&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;MODE_EMPHASIZED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;MODE_DOUBLE_HEIGHT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;MODE_DOUBLE_WIDTH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;MODE_UNDERLINE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$modes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$bits&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_pad&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;decbin&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$modes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;STR_PAD_LEFT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$mode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$j&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$j&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;strlen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$bits&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$j&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;substr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$bits&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$j&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;nv&#34;&gt;$mode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$modes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$j&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectPrintMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$mode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ABCDEFGHIJabcdefghijk&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;selectPrintMode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Reset
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-printmodes&#34;
      id=&#34;tabs-post-2014-11-escpos-printmodes-3&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-printmodes-3&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Hexdump
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000000  1b 40 1b 21 00 41 42 43  44 45 46 47 48 49 4a 61  |.@.!.ABCDEFGHIJa|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000010  62 63 64 65 66 67 68 69  6a 6b 0a 1b 21 80 41 42  |bcdefghijk..!.AB|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000020  43 44 45 46 47 48 49 4a  61 62 63 64 65 66 67 68  |CDEFGHIJabcdefgh|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000030  69 6a 6b 0a 1b 21 20 41  42 43 44 45 46 47 48 49  |ijk..! ABCDEFGHI|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000040  4a 61 62 63 64 65 66 67  68 69 6a 6b 0a 1b 21 a0  |Jabcdefghijk..!.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000050  41 42 43 44 45 46 47 48  49 4a 61 62 63 64 65 66  |ABCDEFGHIJabcdef|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000060  67 68 69 6a 6b 0a 1b 21  10 41 42 43 44 45 46 47  |ghijk..!.ABCDEFG|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000070  48 49 4a 61 62 63 64 65  66 67 68 69 6a 6b 0a 1b  |HIJabcdefghijk..|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000080  21 90 41 42 43 44 45 46  47 48 49 4a 61 62 63 64  |!.ABCDEFGHIJabcd|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000090  65 66 67 68 69 6a 6b 0a  1b 21 30 41 42 43 44 45  |efghijk..!0ABCDE|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000000a0  46 47 48 49 4a 61 62 63  64 65 66 67 68 69 6a 6b  |FGHIJabcdefghijk|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000000b0  0a 1b 21 b0 41 42 43 44  45 46 47 48 49 4a 61 62  |..!.ABCDEFGHIJab|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000000c0  63 64 65 66 67 68 69 6a  6b 0a 1b 21 08 41 42 43  |cdefghijk..!.ABC|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000000d0  44 45 46 47 48 49 4a 61  62 63 64 65 66 67 68 69  |DEFGHIJabcdefghi|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000000e0  6a 6b 0a 1b 21 88 41 42  43 44 45 46 47 48 49 4a  |jk..!.ABCDEFGHIJ|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000000f0  61 62 63 64 65 66 67 68  69 6a 6b 0a 1b 21 28 41  |abcdefghijk..!(A|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000100  42 43 44 45 46 47 48 49  4a 61 62 63 64 65 66 67  |BCDEFGHIJabcdefg|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000110  68 69 6a 6b 0a 1b 21 a8  41 42 43 44 45 46 47 48  |hijk..!.ABCDEFGH|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000120  49 4a 61 62 63 64 65 66  67 68 69 6a 6b 0a 1b 21  |IJabcdefghijk..!|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000130  18 41 42 43 44 45 46 47  48 49 4a 61 62 63 64 65  |.ABCDEFGHIJabcde|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000140  66 67 68 69 6a 6b 0a 1b  21 98 41 42 43 44 45 46  |fghijk..!.ABCDEF|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000150  47 48 49 4a 61 62 63 64  65 66 67 68 69 6a 6b 0a  |GHIJabcdefghijk.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000160  1b 21 38 41 42 43 44 45  46 47 48 49 4a 61 62 63  |.!8ABCDEFGHIJabc|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000170  64 65 66 67 68 69 6a 6b  0a 1b 21 b8 41 42 43 44  |defghijk..!.ABCD|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000180  45 46 47 48 49 4a 61 62  63 64 65 66 67 68 69 6a  |EFGHIJabcdefghij|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000190  6b 0a 1b 21 01 41 42 43  44 45 46 47 48 49 4a 61  |k..!.ABCDEFGHIJa|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000001a0  62 63 64 65 66 67 68 69  6a 6b 0a 1b 21 81 41 42  |bcdefghijk..!.AB|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000001b0  43 44 45 46 47 48 49 4a  61 62 63 64 65 66 67 68  |CDEFGHIJabcdefgh|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000001c0  69 6a 6b 0a 1b 21 21 41  42 43 44 45 46 47 48 49  |ijk..!!ABCDEFGHI|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000001d0  4a 61 62 63 64 65 66 67  68 69 6a 6b 0a 1b 21 a1  |Jabcdefghijk..!.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000001e0  41 42 43 44 45 46 47 48  49 4a 61 62 63 64 65 66  |ABCDEFGHIJabcdef|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000001f0  67 68 69 6a 6b 0a 1b 21  11 41 42 43 44 45 46 47  |ghijk..!.ABCDEFG|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000200  48 49 4a 61 62 63 64 65  66 67 68 69 6a 6b 0a 1b  |HIJabcdefghijk..|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000210  21 91 41 42 43 44 45 46  47 48 49 4a 61 62 63 64  |!.ABCDEFGHIJabcd|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000220  65 66 67 68 69 6a 6b 0a  1b 21 31 41 42 43 44 45  |efghijk..!1ABCDE|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000230  46 47 48 49 4a 61 62 63  64 65 66 67 68 69 6a 6b  |FGHIJabcdefghijk|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000240  0a 1b 21 b1 41 42 43 44  45 46 47 48 49 4a 61 62  |..!.ABCDEFGHIJab|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000250  63 64 65 66 67 68 69 6a  6b 0a 1b 21 09 41 42 43  |cdefghijk..!.ABC|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000260  44 45 46 47 48 49 4a 61  62 63 64 65 66 67 68 69  |DEFGHIJabcdefghi|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000270  6a 6b 0a 1b 21 89 41 42  43 44 45 46 47 48 49 4a  |jk..!.ABCDEFGHIJ|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000280  61 62 63 64 65 66 67 68  69 6a 6b 0a 1b 21 29 41  |abcdefghijk..!)A|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000290  42 43 44 45 46 47 48 49  4a 61 62 63 64 65 66 67  |BCDEFGHIJabcdefg|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000002a0  68 69 6a 6b 0a 1b 21 a9  41 42 43 44 45 46 47 48  |hijk..!.ABCDEFGH|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000002b0  49 4a 61 62 63 64 65 66  67 68 69 6a 6b 0a 1b 21  |IJabcdefghijk..!|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000002c0  19 41 42 43 44 45 46 47  48 49 4a 61 62 63 64 65  |.ABCDEFGHIJabcde|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000002d0  66 67 68 69 6a 6b 0a 1b  21 99 41 42 43 44 45 46  |fghijk..!.ABCDEF|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000002e0  47 48 49 4a 61 62 63 64  65 66 67 68 69 6a 6b 0a  |GHIJabcdefghijk.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000002f0  1b 21 39 41 42 43 44 45  46 47 48 49 4a 61 62 63  |.!9ABCDEFGHIJabc|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000300  64 65 66 67 68 69 6a 6b  0a 1b 21 b9 41 42 43 44  |defghijk..!.ABCD|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000310  45 46 47 48 49 4a 61 62  63 64 65 66 67 68 69 6a  |EFGHIJabcdefghij|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000320  6b 0a 1b 21 00 41 42 43  44 45 46 47 48 49 4a 61  |k..!.ABCDEFGHIJa|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000330  62 63 64 65 66 67 68 69  6a 6b 0a 1b 21 80 41 42  |bcdefghijk..!.AB|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000340  43 44 45 46 47 48 49 4a  61 62 63 64 65 66 67 68  |CDEFGHIJabcdefgh|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000350  69 6a 6b 0a 1b 21 20 41  42 43 44 45 46 47 48 49  |ijk..! ABCDEFGHI|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000360  4a 61 62 63 64 65 66 67  68 69 6a 6b 0a 1b 21 a0  |Jabcdefghijk..!.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000370  41 42 43 44 45 46 47 48  49 4a 61 62 63 64 65 66  |ABCDEFGHIJabcdef|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000380  67 68 69 6a 6b 0a 1b 21  10 41 42 43 44 45 46 47  |ghijk..!.ABCDEFG|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000390  48 49 4a 61 62 63 64 65  66 67 68 69 6a 6b 0a 1b  |HIJabcdefghijk..|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000003a0  21 90 41 42 43 44 45 46  47 48 49 4a 61 62 63 64  |!.ABCDEFGHIJabcd|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000003b0  65 66 67 68 69 6a 6b 0a  1b 21 30 41 42 43 44 45  |efghijk..!0ABCDE|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000003c0  46 47 48 49 4a 61 62 63  64 65 66 67 68 69 6a 6b  |FGHIJabcdefghijk|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000003d0  0a 1b 21 b0 41 42 43 44  45 46 47 48 49 4a 61 62  |..!.ABCDEFGHIJab|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000003e0  63 64 65 66 67 68 69 6a  6b 0a 1b 21 08 41 42 43  |cdefghijk..!.ABC|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000003f0  44 45 46 47 48 49 4a 61  62 63 64 65 66 67 68 69  |DEFGHIJabcdefghi|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000400  6a 6b 0a 1b 21 88 41 42  43 44 45 46 47 48 49 4a  |jk..!.ABCDEFGHIJ|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000410  61 62 63 64 65 66 67 68  69 6a 6b 0a 1b 21 28 41  |abcdefghijk..!(A|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000420  42 43 44 45 46 47 48 49  4a 61 62 63 64 65 66 67  |BCDEFGHIJabcdefg|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000430  68 69 6a 6b 0a 1b 21 a8  41 42 43 44 45 46 47 48  |hijk..!.ABCDEFGH|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000440  49 4a 61 62 63 64 65 66  67 68 69 6a 6b 0a 1b 21  |IJabcdefghijk..!|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000450  18 41 42 43 44 45 46 47  48 49 4a 61 62 63 64 65  |.ABCDEFGHIJabcde|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000460  66 67 68 69 6a 6b 0a 1b  21 98 41 42 43 44 45 46  |fghijk..!.ABCDEF|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000470  47 48 49 4a 61 62 63 64  65 66 67 68 69 6a 6b 0a  |GHIJabcdefghijk.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000480  1b 21 38 41 42 43 44 45  46 47 48 49 4a 61 62 63  |.!8ABCDEFGHIJabc|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000490  64 65 66 67 68 69 6a 6b  0a 1b 21 b8 41 42 43 44  |defghijk..!.ABCD|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000004a0  45 46 47 48 49 4a 61 62  63 64 65 66 67 68 69 6a  |EFGHIJabcdefghij|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000004b0  6b 0a 1b 21 01 41 42 43  44 45 46 47 48 49 4a 61  |k..!.ABCDEFGHIJa|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000004c0  62 63 64 65 66 67 68 69  6a 6b 0a 1b 21 81 41 42  |bcdefghijk..!.AB|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000004d0  43 44 45 46 47 48 49 4a  61 62 63 64 65 66 67 68  |CDEFGHIJabcdefgh|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000004e0  69 6a 6b 0a 1b 21 21 41  42 43 44 45 46 47 48 49  |ijk..!!ABCDEFGHI|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000004f0  4a 61 62 63 64 65 66 67  68 69 6a 6b 0a 1b 21 a1  |Jabcdefghijk..!.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000500  41 42 43 44 45 46 47 48  49 4a 61 62 63 64 65 66  |ABCDEFGHIJabcdef|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000510  67 68 69 6a 6b 0a 1b 21  11 41 42 43 44 45 46 47  |ghijk..!.ABCDEFG|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000520  48 49 4a 61 62 63 64 65  66 67 68 69 6a 6b 0a 1b  |HIJabcdefghijk..|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000530  21 91 41 42 43 44 45 46  47 48 49 4a 61 62 63 64  |!.ABCDEFGHIJabcd|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000540  65 66 67 68 69 6a 6b 0a  1b 21 31 41 42 43 44 45  |efghijk..!1ABCDE|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000550  46 47 48 49 4a 61 62 63  64 65 66 67 68 69 6a 6b  |FGHIJabcdefghijk|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000560  0a 1b 21 b1 41 42 43 44  45 46 47 48 49 4a 61 62  |..!.ABCDEFGHIJab|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000570  63 64 65 66 67 68 69 6a  6b 0a 1b 21 09 41 42 43  |cdefghijk..!.ABC|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000580  44 45 46 47 48 49 4a 61  62 63 64 65 66 67 68 69  |DEFGHIJabcdefghi|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000590  6a 6b 0a 1b 21 89 41 42  43 44 45 46 47 48 49 4a  |jk..!.ABCDEFGHIJ|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000005a0  61 62 63 64 65 66 67 68  69 6a 6b 0a 1b 21 29 41  |abcdefghijk..!)A|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000005b0  42 43 44 45 46 47 48 49  4a 61 62 63 64 65 66 67  |BCDEFGHIJabcdefg|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000005c0  68 69 6a 6b 0a 1b 21 a9  41 42 43 44 45 46 47 48  |hijk..!.ABCDEFGH|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000005d0  49 4a 61 62 63 64 65 66  67 68 69 6a 6b 0a 1b 21  |IJabcdefghijk..!|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000005e0  19 41 42 43 44 45 46 47  48 49 4a 61 62 63 64 65  |.ABCDEFGHIJabcde|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;000005f0  66 67 68 69 6a 6b 0a 1b  21 99 41 42 43 44 45 46  |fghijk..!.ABCDEF|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000600  47 48 49 4a 61 62 63 64  65 66 67 68 69 6a 6b 0a  |GHIJabcdefghijk.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000610  1b 21 39 41 42 43 44 45  46 47 48 49 4a 61 62 63  |.!9ABCDEFGHIJabc|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000620  64 65 66 67 68 69 6a 6b  0a 1b 21 b9 41 42 43 44  |defghijk..!.ABCD|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000630  45 46 47 48 49 4a 61 62  63 64 65 66 67 68 69 6a  |EFGHIJabcdefghij|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000640  6b 0a 1b 21 00 1d 56 41  03                       |k..!..VA.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000649
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3 id=&#34;underline&#34;&gt;Underline
&lt;/h3&gt;


&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-underline&#34;
      id=&#34;tabs-post-2014-11-escpos-underline-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-underline-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-04.png&#34;
	width=&#34;600&#34;
	height=&#34;135&#34;
	srcset=&#34;https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-04_hu_227fa3239f19e712.png 480w, https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-04_hu_92124d82f4e023d4.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;444&#34;
		data-flex-basis=&#34;1066px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-underline&#34;
      id=&#34;tabs-post-2014-11-escpos-underline-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-underline-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Command
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;dl&gt;
&lt;dt&gt;The command is:&lt;/dt&gt;
&lt;dd&gt;ESC - [ number ]&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;The argument is set to 0 for no underline, 1 for underline, 2 for heavy underline.&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-underline&#34;
      id=&#34;tabs-post-2014-11-escpos-underline-2&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-underline-2&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Underline */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setUnderline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;The quick brown fox jumps over the lazy dog&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setUnderline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Reset
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-underline&#34;
      id=&#34;tabs-post-2014-11-escpos-underline-3&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-underline-3&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Hexdump
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000000  1b 40 1b 2d 00 54 68 65  20 71 75 69 63 6b 20 62  |.@.-.The quick b|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000010  72 6f 77 6e 20 66 6f 78  20 6a 75 6d 70 73 20 6f  |rown fox jumps o|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000020  76 65 72 20 74 68 65 20  6c 61 7a 79 20 64 6f 67  |ver the lazy dog|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000030  0a 1b 2d 01 54 68 65 20  71 75 69 63 6b 20 62 72  |..-.The quick br|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000040  6f 77 6e 20 66 6f 78 20  6a 75 6d 70 73 20 6f 76  |own fox jumps ov|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000050  65 72 20 74 68 65 20 6c  61 7a 79 20 64 6f 67 0a  |er the lazy dog.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000060  1b 2d 02 54 68 65 20 71  75 69 63 6b 20 62 72 6f  |.-.The quick bro|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000070  77 6e 20 66 6f 78 20 6a  75 6d 70 73 20 6f 76 65  |wn fox jumps ove|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000080  72 20 74 68 65 20 6c 61  7a 79 20 64 6f 67 0a 1b  |r the lazy dog..|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000090  2d 00 1d 56 41 03                                 |-..VA.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000096
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3 id=&#34;cuts&#34;&gt;Cuts
&lt;/h3&gt;


&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-cuts&#34;
      id=&#34;tabs-post-2014-11-escpos-cuts-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-cuts-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Command
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;dl&gt;
&lt;dt&gt;The command is:&lt;/dt&gt;
&lt;dd&gt;ESC V [ number ]&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;The argument apparently represents whether to perform a &amp;lsquo;partial&amp;rsquo; (65) or &amp;lsquo;full&amp;rsquo; (66) cut, but has no effect on my model of printer.&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-cuts&#34;
      id=&#34;tabs-post-2014-11-escpos-cuts-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-cuts-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Cuts */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;CUT_PARTIAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;CUT_FULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-cuts&#34;
      id=&#34;tabs-post-2014-11-escpos-cuts-2&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-cuts-2&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Hexdump
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000000  1b 40 1d 56 42 03 1d 56  41 03 1d 56 42 03 1d 56  |.@.VB..VA..VB..V|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000010  41 03 1d 56 42 03 1d 56  41 03 1d 56 42 03 1d 56  |A..VB..VA..VB..V|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000020  41 03 1d 56 42 03 1d 56  41 03 1d 56 41 03        |A..VB..VA..VA.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0000002e
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3 id=&#34;emphasis&#34;&gt;Emphasis
&lt;/h3&gt;


&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-emphasis&#34;
      id=&#34;tabs-post-2014-11-escpos-emphasis-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-emphasis-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-05.png&#34;
	width=&#34;600&#34;
	height=&#34;104&#34;
	srcset=&#34;https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-05_hu_40d98fbeb037ea59.png 480w, https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-05_hu_d00cbbad99c254d7.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;576&#34;
		data-flex-basis=&#34;1384px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-emphasis&#34;
      id=&#34;tabs-post-2014-11-escpos-emphasis-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-emphasis-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Command
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;dl&gt;
&lt;dt&gt;The command is:&lt;/dt&gt;
&lt;dd&gt;
&lt;p&gt;ESC E [ number ]&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;Use 1 to enable emphasis, and 0 to disable it.&lt;/p&gt;
&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-emphasis&#34;
      id=&#34;tabs-post-2014-11-escpos-emphasis-2&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-emphasis-2&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Emphasis */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setEmphasis&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;The quick brown fox jumps over the lazy dog&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setEmphasis&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Reset
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-emphasis&#34;
      id=&#34;tabs-post-2014-11-escpos-emphasis-3&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-emphasis-3&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Hexdump
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000000  1b 40 1b 45 00 54 68 65  20 71 75 69 63 6b 20 62  |.@.E.The quick b|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000010  72 6f 77 6e 20 66 6f 78  20 6a 75 6d 70 73 20 6f  |rown fox jumps o|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000020  76 65 72 20 74 68 65 20  6c 61 7a 79 20 64 6f 67  |ver the lazy dog|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000030  0a 1b 45 01 54 68 65 20  71 75 69 63 6b 20 62 72  |..E.The quick br|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000040  6f 77 6e 20 66 6f 78 20  6a 75 6d 70 73 20 6f 76  |own fox jumps ov|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000050  65 72 20 74 68 65 20 6c  61 7a 79 20 64 6f 67 0a  |er the lazy dog.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000060  1b 45 00 1d 56 41 03                              |.E..VA.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000067
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3 id=&#34;double-strike&#34;&gt;Double-strike
&lt;/h3&gt;


&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-doublestrike&#34;
      id=&#34;tabs-post-2014-11-escpos-doublestrike-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-doublestrike-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-06.png&#34;
	width=&#34;600&#34;
	height=&#34;102&#34;
	srcset=&#34;https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-06_hu_aaf87cd9df2f482c.png 480w, https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-06_hu_3b4bfe5e674603d5.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;588&#34;
		data-flex-basis=&#34;1411px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-doublestrike&#34;
      id=&#34;tabs-post-2014-11-escpos-doublestrike-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-doublestrike-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Command
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;dl&gt;
&lt;dt&gt;The command is:&lt;/dt&gt;
&lt;dd&gt;ESC G [ number ]&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;Use 1 to enable, or 0 to disable. On the model tested here, this appears to be identical to the &amp;ldquo;emphasis&amp;rdquo; mode above.&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-doublestrike&#34;
      id=&#34;tabs-post-2014-11-escpos-doublestrike-2&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-doublestrike-2&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Double-strike (looks basically the same as emphasis) */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setDoubleStrike&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;The quick brown fox jumps over the lazy dog&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setDoubleStrike&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-doublestrike&#34;
      id=&#34;tabs-post-2014-11-escpos-doublestrike-3&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-doublestrike-3&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Hexdump
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000000  1b 40 1b 47 00 54 68 65  20 71 75 69 63 6b 20 62  |.@.G.The quick b|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000010  72 6f 77 6e 20 66 6f 78  20 6a 75 6d 70 73 20 6f  |rown fox jumps o|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000020  76 65 72 20 74 68 65 20  6c 61 7a 79 20 64 6f 67  |ver the lazy dog|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000030  0a 1b 47 01 54 68 65 20  71 75 69 63 6b 20 62 72  |..G.The quick br|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000040  6f 77 6e 20 66 6f 78 20  6a 75 6d 70 73 20 6f 76  |own fox jumps ov|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000050  65 72 20 74 68 65 20 6c  61 7a 79 20 64 6f 67 0a  |er the lazy dog.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000060  1b 47 00 1d 56 41 03                              |.G..VA.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000067
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3 id=&#34;fonts&#34;&gt;Fonts
&lt;/h3&gt;


&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-fonts&#34;
      id=&#34;tabs-post-2014-11-escpos-fonts-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-fonts-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-07.png&#34;
	width=&#34;600&#34;
	height=&#34;124&#34;
	srcset=&#34;https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-07_hu_c73840273b02f81c.png 480w, https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-07_hu_204a247ef42570b1.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;483&#34;
		data-flex-basis=&#34;1161px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-fonts&#34;
      id=&#34;tabs-post-2014-11-escpos-fonts-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-fonts-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Command
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;dl&gt;
&lt;dt&gt;The command is:&lt;/dt&gt;
&lt;dd&gt;ESC M [ number ]&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;There are three possible fonts, documented as &amp;ldquo;A&amp;rdquo;, &amp;ldquo;B&amp;rdquo; and &amp;ldquo;C&amp;rdquo;, and numbered 0, 1, and 2. Many printers, including this one, don&amp;rsquo;t have Font C.&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-fonts&#34;
      id=&#34;tabs-post-2014-11-escpos-fonts-2&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-fonts-2&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Fonts (many printers do not have a &amp;#39;Font C&amp;#39;) */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$fonts&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;FONT_A&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;FONT_B&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;FONT_C&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$fonts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setFont&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$fonts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;The quick brown fox jumps over the lazy dog&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setFont&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Reset
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-fonts&#34;
      id=&#34;tabs-post-2014-11-escpos-fonts-3&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-fonts-3&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Hexdump
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000000  1b 40 1b 4d 00 54 68 65  20 71 75 69 63 6b 20 62  |.@.M.The quick b|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000010  72 6f 77 6e 20 66 6f 78  20 6a 75 6d 70 73 20 6f  |rown fox jumps o|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000020  76 65 72 20 74 68 65 20  6c 61 7a 79 20 64 6f 67  |ver the lazy dog|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000030  0a 1b 4d 01 54 68 65 20  71 75 69 63 6b 20 62 72  |..M.The quick br|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000040  6f 77 6e 20 66 6f 78 20  6a 75 6d 70 73 20 6f 76  |own fox jumps ov|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000050  65 72 20 74 68 65 20 6c  61 7a 79 20 64 6f 67 0a  |er the lazy dog.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000060  1b 4d 02 54 68 65 20 71  75 69 63 6b 20 62 72 6f  |.M.The quick bro|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000070  77 6e 20 66 6f 78 20 6a  75 6d 70 73 20 6f 76 65  |wn fox jumps ove|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000080  72 20 74 68 65 20 6c 61  7a 79 20 64 6f 67 0a 1b  |r the lazy dog..|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000090  4d 00 1d 56 41 03                                 |M..VA.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000096
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3 id=&#34;justification&#34;&gt;Justification
&lt;/h3&gt;


&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-justification&#34;
      id=&#34;tabs-post-2014-11-escpos-justification-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-justification-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-08.png&#34;
	width=&#34;600&#34;
	height=&#34;113&#34;
	srcset=&#34;https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-08_hu_93f36833e55dec2c.png 480w, https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-08_hu_97df7ddba2a26204.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;530&#34;
		data-flex-basis=&#34;1274px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-justification&#34;
      id=&#34;tabs-post-2014-11-escpos-justification-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-justification-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Command
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;dl&gt;
&lt;dt&gt;The command is:&lt;/dt&gt;
&lt;dd&gt;ESC a [ number ]&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;Use 0 to justify left, 1 to centre the text, or 2 to right-align it.&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-justification&#34;
      id=&#34;tabs-post-2014-11-escpos-justification-2&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-justification-2&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Justification */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$justification&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;JUSTIFY_LEFT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;JUSTIFY_CENTER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;JUSTIFY_RIGHT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$justification&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setJustification&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$justification&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;A man a plan a canal panama&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setJustification&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Reset
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-justification&#34;
      id=&#34;tabs-post-2014-11-escpos-justification-3&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-justification-3&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Hexdump
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000000  1b 40 1b 61 00 41 20 6d  61 6e 20 61 20 70 6c 61  |.@.a.A man a pla|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000010  6e 20 61 20 63 61 6e 61  6c 20 70 61 6e 61 6d 61  |n a canal panama|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000020  0a 1b 61 01 41 20 6d 61  6e 20 61 20 70 6c 61 6e  |..a.A man a plan|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000030  20 61 20 63 61 6e 61 6c  20 70 61 6e 61 6d 61 0a  | a canal panama.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000040  1b 61 02 41 20 6d 61 6e  20 61 20 70 6c 61 6e 20  |.a.A man a plan |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000050  61 20 63 61 6e 61 6c 20  70 61 6e 61 6d 61 0a 1b  |a canal panama..|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000060  61 00 1d 56 41 03                                 |a..VA.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000066
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3 id=&#34;barcodes&#34;&gt;Barcodes
&lt;/h3&gt;


&lt;div class=&#34;gdoc-tabs&#34;&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-barcodes&#34;
      id=&#34;tabs-post-2014-11-escpos-barcodes-0&#34;
      checked=&#34;checked&#34;
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-barcodes-0&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Example
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;p class=&#34;imgtab&#34;&gt;&lt;img src=&#34;https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-09.png&#34;
	width=&#34;600&#34;
	height=&#34;1044&#34;
	srcset=&#34;https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-09_hu_7db7b7d247b39659.png 480w, https://mike42.me/blog/2014-11-what-is-escpos-and-how-do-i-use-it/2014-11-escpos-09_hu_ddf22f444fe62915.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;57&#34;
		data-flex-basis=&#34;137px&#34;
	
&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-barcodes&#34;
      id=&#34;tabs-post-2014-11-escpos-barcodes-1&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-barcodes-1&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Command
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;dl&gt;
&lt;dt&gt;The commands are:&lt;/dt&gt;
&lt;dd&gt;GS h [ number ]&lt;br/&gt;&lt;/dd&gt;
&lt;dd&gt;ESC k [ number ] [ text ] NUL&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;The first command sets the barcode height — measured in dots, while the second one prints the actual barcode. The number represents the barcode standard, which for most purposes should be &amp;ldquo;4&amp;rdquo;, representing CODE39. 6 standards are supported by the PHP driver.&lt;/p&gt;
&lt;p&gt;You will notice that due to driver glitches or printer incompatibility, not all of the barcodes print! As above, my advice is to use CODE39 if you run into this.&lt;/p&gt;
&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-barcodes&#34;
      id=&#34;tabs-post-2014-11-escpos-barcodes-2&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-barcodes-2&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      PHP
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;__DIR__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/autoload.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Mike42\Escpos\PrintConnectors\FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;FilePrintConnector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/usb/lp0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$connector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Barcodes */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$barcodes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;BARCODE_UPCA&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;BARCODE_UPCE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;BARCODE_JAN13&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;BARCODE_JAN8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;BARCODE_CODE39&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;BARCODE_ITF&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;BARCODE_CODABAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setBarcodeHeight&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$barcodes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Barcode &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; &amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;barcode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;9876&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$barcodes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;feed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;input
      type=&#34;radio&#34;
      class=&#34;gdoc-tabs__control hidden&#34;
      name=&#34;tabs-post-2014-11-escpos-barcodes&#34;
      id=&#34;tabs-post-2014-11-escpos-barcodes-3&#34;
      
    /&gt;
    &lt;label for=&#34;tabs-post-2014-11-escpos-barcodes-3&#34; class=&#34;gdoc-tabs__label&#34;&gt;
      Hexdump
    &lt;/label&gt;
    &lt;div class=&#34;gdoc-markdown--nested gdoc-tabs__content&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000000  1b 40 1d 68 50 42 61 72  63 6f 64 65 20 30 20 0a  |.@.hPBarcode 0 .|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000010  1d 6b 00 39 38 37 36 00  0a 42 61 72 63 6f 64 65  |.k.9876..Barcode|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000020  20 31 20 0a 1d 6b 01 39  38 37 36 00 0a 42 61 72  | 1 ..k.9876..Bar|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000030  63 6f 64 65 20 32 20 0a  1d 6b 02 39 38 37 36 00  |code 2 ..k.9876.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000040  0a 42 61 72 63 6f 64 65  20 33 20 0a 1d 6b 03 39  |.Barcode 3 ..k.9|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000050  38 37 36 00 0a 42 61 72  63 6f 64 65 20 34 20 0a  |876..Barcode 4 .|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000060  1d 6b 04 39 38 37 36 00  0a 42 61 72 63 6f 64 65  |.k.9876..Barcode|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000070  20 35 20 0a 1d 6b 05 39  38 37 36 00 0a 42 61 72  | 5 ..k.9876..Bar|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000080  63 6f 64 65 20 36 20 0a  1d 6b 06 39 38 37 36 00  |code 6 ..k.9876.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000090  0a 1d 56 41 03                                    |..VA.|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00000095
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2 id=&#34;resources&#34;&gt;Resources
&lt;/h2&gt;&lt;p&gt;Linked previously in this post:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/escpos-php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;escpos-php: Library to work with ESC/POS thermal printers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://web.archive.org/web/20200110095204/http://content.epson.de/fileadmin/content/files/RSD/downloads/escpos.pdf&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Epson FAQ on ESC/POS (via the Internet Archive)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And if you&amp;rsquo;ve just received an Epson printer and need to figure out how it works:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2014-20-26-setting-up-an-epson-receipt-printer&#34; &gt;Setting up an Epson receipt printer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Update 2015-03-10:&lt;/strong&gt; Re-wrote examples for the newer version of &lt;code&gt;escpos-php&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 2016-04-22:&lt;/strong&gt; Updated examples again to match the latest driver code.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Using xte to script your workflow</title>
        <link>https://mike42.me/blog/2014-11-using-xte-to-script-your-workflow</link>
        <pubDate>Fri, 07 Nov 2014 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2014-11-using-xte-to-script-your-workflow</guid>
        <description>&lt;p&gt;In the classic world of desktop automation, &amp;ldquo;macros&amp;rdquo; allow you to repeat a task easily. In general, &lt;code&gt;xte&lt;/code&gt; is the best way of scripting this up on Linux.&lt;/p&gt;
&lt;p&gt;First, you need to install it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install xautomation
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;yum install xautomation
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To use &lt;code&gt;xte&lt;/code&gt;, you need to send it information via a &amp;lsquo;pipe&amp;rsquo;. The &lt;code&gt;man&lt;/code&gt; page covers the key codes and commands in detail, but I&amp;rsquo;ll step through some basic examples below.&lt;/p&gt;
&lt;h2 id=&#34;examples&#34;&gt;Examples
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;ve put together a couple of interesting examples to show some uses for this tool.&lt;/p&gt;
&lt;h3 id=&#34;example-1-do-a-google-search&#34;&gt;Example 1: Do a Google search
&lt;/h3&gt;&lt;p&gt;The example below uses &lt;code&gt;xte&lt;/code&gt; to type &amp;ldquo;Hello world&amp;rdquo; into a text box.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-11-using-xte-to-script-your-workflow/2014-11-xte-hello-world.png&#34;
	width=&#34;517&#34;
	height=&#34;241&#34;
	srcset=&#34;https://mike42.me/blog/2014-11-using-xte-to-script-your-workflow/2014-11-xte-hello-world_hu_7f45933b0386551a.png 480w, https://mike42.me/blog/2014-11-using-xte-to-script-your-workflow/2014-11-xte-hello-world_hu_6a6e2511bfdced8a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;214&#34;
		data-flex-basis=&#34;514px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Type the command, press enter, then quickly click on the text box:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sleep 1 &amp;amp;&amp;amp; echo &amp;#34;Hello world&amp;#34; | xte
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;example-2-open-a-browser-and-search-wikipedia&#34;&gt;Example 2: Open a browser and search Wikipedia
&lt;/h3&gt;&lt;p&gt;To write a script which combines a few commands for &lt;code&gt;xte&lt;/code&gt;, you could put it in a &lt;code&gt;bash&lt;/code&gt; script. Remember to put a pause between commands so that the windowing system can catch up.&lt;/p&gt;
&lt;p&gt;The script below will use Gnome Shells &amp;ldquo;overview mode&amp;rdquo; to launch Chromium, then open a new tab, and search Wikipedia for &amp;ldquo;cars&amp;rdquo;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;xte &lt;span class=&#34;s&#34;&gt;&amp;lt;&amp;lt; EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;key Super_L
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;usleep 100000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;str chromium
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;usleep 100000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;key Return
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;sleep 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;keydown Control_L
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;key t
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;keyup Control_L
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;sleep 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;str https://en.wikipedia.org
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;usleep 100000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;key Return
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;sleep 3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;key Tab
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;usleep 100000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;str cars
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;usleep 100000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;key Return
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;example-3-draw-a-spiral-in-gimp&#34;&gt;Example 3: Draw a spiral in GIMP
&lt;/h3&gt;&lt;p&gt;When you script an operation, you can interact with &lt;em&gt;any&lt;/em&gt; program using a set of rules. Below is a PHP script called &lt;code&gt;spiral.php&lt;/code&gt;, which draws and labels a spiral in GIMP, switching the foreground &amp;amp; background colours at each step.&lt;/p&gt;
&lt;p&gt;This requires an open GIMP window in the correct part of the screen:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-11-using-xte-to-script-your-workflow/2014-11-gimp-spiral.png&#34;
	width=&#34;907&#34;
	height=&#34;792&#34;
	srcset=&#34;https://mike42.me/blog/2014-11-using-xte-to-script-your-workflow/2014-11-gimp-spiral_hu_7ced873dc6a17291.png 480w, https://mike42.me/blog/2014-11-using-xte-to-script-your-workflow/2014-11-gimp-spiral_hu_ec958783bdf9ae23.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;114&#34;
		data-flex-basis=&#34;274px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The interaction in this case is quite simple for a computer, but would be tedious to do manually:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;strong&gt;N&lt;/strong&gt;&lt;/dt&gt;
&lt;dd&gt;Open the Line tool&lt;/dd&gt;
&lt;dt&gt;&lt;strong&gt;T&lt;/strong&gt;&lt;/dt&gt;
&lt;dd&gt;Open the Text tool&lt;/dd&gt;
&lt;dt&gt;&lt;strong&gt;X&lt;/strong&gt;&lt;/dt&gt;
&lt;dd&gt;Swap foreground &amp;amp; background colours&lt;/dd&gt;
&lt;dt&gt;&lt;strong&gt;Click &amp;amp; Drag&lt;/strong&gt;&lt;/dt&gt;
&lt;dd&gt;Draw a line&lt;/dd&gt;
&lt;/dl&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#!/usr/bin/env php
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sleep&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;N&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;usleep&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Where the canvas is on-screen
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$top_x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;150&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$top_y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;150&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$canvas_width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;400&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Spiral properties
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$pi&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;3.14159265358979&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$centre_x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$top_x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$canvas_width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$centre_y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$top_y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$canvas_width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$spins&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Centre the mouse
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;mousemove &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$centre_x&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$centre_y\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;usleep 100000&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Draw a spiral
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;0.005&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$angle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$spins&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$pi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$radius&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$canvas_width&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$centre_x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$radius&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;cos&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$angle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$centre_y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$radius&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sin&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$angle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;mousedown 1&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;mousemove &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$x&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$y\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;usleep 100000&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;mouseup 1&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;key X&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Label the spiral
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;mousemove &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$centre_x&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$top_y\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;key T&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;usleep 100000&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;mouseclick 1&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;usleep 100000&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;str Spiral&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After cropping, the spiral image on its own is:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-11-using-xte-to-script-your-workflow/2014-11-spiral.png&#34;
	width=&#34;316&#34;
	height=&#34;363&#34;
	srcset=&#34;https://mike42.me/blog/2014-11-using-xte-to-script-your-workflow/2014-11-spiral_hu_2e14f3a3d18c85ee.png 480w, https://mike42.me/blog/2014-11-using-xte-to-script-your-workflow/2014-11-spiral_hu_ee78014ba2084d0.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;87&#34;
		data-flex-basis=&#34;208px&#34;
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;example-4-forward-emails&#34;&gt;Example 4: Forward emails
&lt;/h3&gt;&lt;p&gt;Google&amp;rsquo;s Gmail web interface has keyboard shortcuts for quick navigation. This example uses:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;strong&gt;f&lt;/strong&gt;&lt;/dt&gt;
&lt;dd&gt;Forward an email&lt;/dd&gt;
&lt;dt&gt;&lt;strong&gt;Tab&lt;/strong&gt;&lt;/dt&gt;
&lt;dd&gt;Move between fields&lt;/dd&gt;
&lt;dt&gt;&lt;strong&gt;Ctrl+Enter&lt;/strong&gt;&lt;/dt&gt;
&lt;dd&gt;Send&lt;/dd&gt;
&lt;dt&gt;&lt;strong&gt;j&lt;/strong&gt;&lt;/dt&gt;
&lt;dd&gt;Next email&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;Using these shortcuts, this script, &lt;code&gt;forward.txt&lt;/code&gt;, will forward an  email too &lt;code&gt;bob@email.com&lt;/code&gt; and &lt;code&gt;fred@example.com&lt;/code&gt;, then navigate to the next email:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sleep 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;key f
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sleep 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;str bob@example.com
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sleep 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;str fred@example.com
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sleep 0.1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;key Return
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sleep 3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;key Return
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sleep 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;key Tab
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sleep 0.1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;keydown Control_L
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;key Return
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;keyup Control_L
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sleep 3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;key j
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sleep 2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To send one email through &lt;code&gt;xte&lt;/code&gt;, you could run this, and then click over to an open email in Gmail:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat forward.txt | xte
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To send the next 106 emails (e.g. in a label or search), you could instead type:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; i in &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;1..106&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;cat forward.txt &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; xte&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is not fool-proof, so you would need to adjust the timing if your Internet connection is laggy.&lt;/p&gt;
&lt;h2 id=&#34;when-to-use-xte&#34;&gt;When to use xte
&lt;/h2&gt;&lt;p&gt;Usually, a task which is &lt;em&gt;supposed&lt;/em&gt; to be automated will have an API. For example, GIMP provides a python plugin interface, Gmail can be accessed via IMAP, and Google and Wikipedia searches can be done directly through HTTP. This is always the best way to do things.&lt;/p&gt;
&lt;p&gt;However, the automation junkie should have &lt;code&gt;xte&lt;/code&gt; in their toolkit, for situations where proper automation is not practical, such as when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;you don&amp;rsquo;t want to learn an API, to only use it for one day.&lt;/li&gt;
&lt;li&gt;you&amp;rsquo;re doing a repetitive task in a program or website which is feature-poor.&lt;/li&gt;
&lt;li&gt;you need to test some feature repeatedly under different circumstances.&lt;/li&gt;
&lt;li&gt;you find a game which requires you to click fast.&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>Setting up an Epson receipt printer</title>
        <link>https://mike42.me/blog/2014-10-setting-up-an-epson-receipt-printer</link>
        <pubDate>Sat, 25 Oct 2014 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2014-10-setting-up-an-epson-receipt-printer</guid>
        <description>&lt;p&gt;I recently picked up one of these networked thermal receipt printers.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-10-setting-up-an-epson-receipt-printer/2014-10-epson.jpg&#34;
	width=&#34;600&#34;
	height=&#34;450&#34;
	srcset=&#34;https://mike42.me/blog/2014-10-setting-up-an-epson-receipt-printer/2014-10-epson_hu_f990d98378adf295.jpg 480w, https://mike42.me/blog/2014-10-setting-up-an-epson-receipt-printer/2014-10-epson_hu_2f2e474ef385e49d.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Epson receipt printer&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-10-setting-up-an-epson-receipt-printer/2014-10-epson-open.jpg&#34;
	width=&#34;450&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-10-setting-up-an-epson-receipt-printer/2014-10-epson-open_hu_4171972a4397ed67.jpg 480w, https://mike42.me/blog/2014-10-setting-up-an-epson-receipt-printer/2014-10-epson-open_hu_8c9acd60bbc277ec.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;An open Epson receipt printer&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;75&#34;
		data-flex-basis=&#34;180px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Being Point-of-Sale equipment, these come from a different tradition of printing, and have only a few things in common with regular laser printers. This post will cover the basic steps to getting the printer up and running.&lt;/p&gt;
&lt;p&gt;This one has the model number &lt;a class=&#34;link&#34; href=&#34;http://www.epson.com.au/pos/products/receiptprinters/DisplaySpecs.asp?id=tmt82ii&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;TM-T82II&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;setting-up-the-printer&#34;&gt;Setting up the printer
&lt;/h2&gt;&lt;p&gt;Firstly, this particular printer only has an ethernet interface, which comes configured with a static IP by default, rather than DHCP. Holding the button next to the network port prints out the settings:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-10-setting-up-an-epson-receipt-printer/2014-10-epson-card.jpg&#34;
	width=&#34;600&#34;
	height=&#34;450&#34;
	srcset=&#34;https://mike42.me/blog/2014-10-setting-up-an-epson-receipt-printer/2014-10-epson-card_hu_cd409e8aea15ff40.jpg 480w, https://mike42.me/blog/2014-10-setting-up-an-epson-receipt-printer/2014-10-epson-card_hu_262273019dd5e0b0.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Epson receipt printer network card.&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-10-setting-up-an-epson-receipt-printer/2014-10-epson-network.jpg&#34;
	width=&#34;600&#34;
	height=&#34;935&#34;
	srcset=&#34;https://mike42.me/blog/2014-10-setting-up-an-epson-receipt-printer/2014-10-epson-network_hu_d427ac5f5e79fee1.jpg 480w, https://mike42.me/blog/2014-10-setting-up-an-epson-receipt-printer/2014-10-epson-network_hu_9866632089e5b9e1.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Epson receipt printer network settings.&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;64&#34;
		data-flex-basis=&#34;154px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The IP address of the printer is shown 192.168.192.168, and subnet mask 255.255.255.0. To speak to it, we need a computer on the same subnet. In this case the last number of the IP address is the only part which needs to be different.&lt;/p&gt;
&lt;p&gt;On GNU/Linux, this is best done with &lt;code&gt;ifconfig&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo ifconfig eth0 192.168.192.169 netmask 255.255.255.0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you used the correct interface, address and netmask, then you should now be able to ping the printer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo ifconfig
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;eth0      Link encap:Ethernet  HWaddr ...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          inet addr:192.168.192.169  Bcast:192.168.192.255  Mask:255.255.255.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          ...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ping 192.168.192.168
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PING 192.168.192.168 (192.168.192.168) 56(84) bytes of data.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;64 bytes from 192.168.192.168: icmp_seq=1 ttl=255 time=1.09 ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;64 bytes from 192.168.192.168: icmp_seq=2 ttl=255 time=0.506 ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The printer has a web interface, and is open on two ports for printing:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ nmap 192.168.192.168
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PORT     STATE SERVICE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;80/tcp   open  http
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;515/tcp  open  printer
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;9100/tcp open  jetdirect
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The web interface will let you set different IP settings, so that you can get the printer on your network. If you mess up and can&amp;rsquo;t connect, then do a factory reset: Hold the button used before, and then reboot the printer.&lt;/p&gt;
&lt;h2 id=&#34;using-the-printer&#34;&gt;Using the printer
&lt;/h2&gt;&lt;p&gt;Epson provides drivers for several platforms, which may fit your use case.&lt;/p&gt;
&lt;p&gt;However, these printers do support ESC/POS (See &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/ESC/P&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Wikipedia&lt;/a&gt;). making it quite accessible without installed drivers.&lt;/p&gt;
&lt;p&gt;The printer will immediately print any regular text it receives over Port 9100, line by line:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello World&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; nc 192.168.192.168 &lt;span class=&#34;m&#34;&gt;9100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ESC/POS commands allow you to format the text, print barcodes, and cut the paper. A good resource for them is &lt;a class=&#34;link&#34; href=&#34;https://web.archive.org/web/20200110095204/http://content.epson.de/fileadmin/content/files/RSD/downloads/escpos.pdf&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this PDF reference from Epson&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve included a PHP script to produce the ESC/POS commands for the below receipt, showing how to use a few of the supported features:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-10-setting-up-an-epson-receipt-printer/2014-10-epson-example.jpg&#34;
	width=&#34;600&#34;
	height=&#34;477&#34;
	srcset=&#34;https://mike42.me/blog/2014-10-setting-up-an-epson-receipt-printer/2014-10-epson-example_hu_1e94a3a7eda36593.jpg 480w, https://mike42.me/blog/2014-10-setting-up-an-epson-receipt-printer/2014-10-epson-example_hu_df74cfd3d77a349d.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Example receipt from an Epson receipt printer, printed using PHP&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;125&#34;
		data-flex-basis=&#34;301px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;And the script which created it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* ASCII constants */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ESC&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x1b&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;GS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x1d&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;NUL&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x00&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Output an example receipt */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ESC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;@&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Reset to defaults
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ESC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;E&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Bold
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;FOO CORP Ltd.&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Company
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ESC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;E&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Not Bold
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ESC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Blank line
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Receipt for whatever&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Print text
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ESC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 4 Blank lines
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Bar-code at the end */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ESC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Centered printing
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;GS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;k&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;987654321&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;NUL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Print barcode
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ESC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Blank line
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;987654321&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Print number
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;GS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;V&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\x41&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Cut
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This can again be sent to the printer using netcat:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;php foo.php &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; nc 192.168.192.168 &lt;span class=&#34;m&#34;&gt;9100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>Productivity: De-activate social networking on a schedule with cron</title>
        <link>https://mike42.me/blog/2014-10-productivity-de-activate-social-networking-on-a-schedule-with-cron</link>
        <pubDate>Fri, 17 Oct 2014 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2014-10-productivity-de-activate-social-networking-on-a-schedule-with-cron</guid>
        <description>&lt;p&gt;Sometimes you need to block out distractions for a set amount of time. One of these is social networking, and it&amp;rsquo;s fairly early to temporarily break it (all for productivity of course!).&lt;/p&gt;
&lt;p&gt;Mac or Linux users can prevent themselves from accessing &lt;code&gt;example.com&lt;/code&gt; like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;echo &amp;#34;127.0.0.1 example.com www.example.com&amp;#34; &amp;gt;&amp;gt; /etc/hosts
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This tells the computer that it hosts &lt;code&gt;example.com&lt;/code&gt;, so it won&amp;rsquo;t load it from the internet.&lt;/p&gt;
&lt;p&gt;And to compliment this, we have &lt;code&gt;sed&lt;/code&gt;, which can delete lines from a file in-place based on a pattern:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sed -i &amp;#39;/example.com/d&amp;#39; /etc/hosts
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Replace &lt;code&gt;example.com&lt;/code&gt; above with your social network of choice, and have a shot. It will take a few minutes to have an effect, because of open connections and your computer&amp;rsquo;s DNS cache.&lt;/p&gt;
&lt;h2 id=&#34;scheduling-it-in&#34;&gt;Scheduling it in
&lt;/h2&gt;&lt;p&gt;Cron is the go-to solution for scheduling any command on Unix. We&amp;rsquo;ll run this as &lt;code&gt;root&lt;/code&gt;, as normal users don&amp;rsquo;t have permission to edit &lt;code&gt;/etc/hosts&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;su
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;crontab -e
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If prompted, select &lt;code&gt;nano&lt;/code&gt; as an editor.&lt;/p&gt;
&lt;p&gt;If, for example, 6pm - 8pm weekdays is a distraction-free time for you, you would schedule the first command for 18:00 on days 1-5, and the second for 20:00 on days 1-5:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# m h  dom mon dow   command
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0 18 * * 1-5 echo &amp;#34;127.0.0.1 example.com www.example.com&amp;#34; &amp;gt;&amp;gt; /etc/hosts
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0 20 * * 1-5 sed -i &amp;#39;/example.com/d&amp;#39; /etc/hosts
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you need something more advanced, consider learning how to use &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/Squid_%28software%29&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;squid&lt;/a&gt; to manage web traffic.&lt;/p&gt;
&lt;h2 id=&#34;when-you-break-something-&#34;&gt;When you break something &amp;hellip;
&lt;/h2&gt;&lt;p&gt;If you accidentally delete your &lt;code&gt;/etc/hosts&lt;/code&gt; while experimenting, you can fetch its contents from &lt;code&gt;/var/lib/dpkg/info/netbase.postinst&lt;/code&gt; (&lt;a class=&#34;link&#34; href=&#34;http://unix.stackexchange.com/questions/11844/etc-hosts-for-debian&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;source&lt;/a&gt;).&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to install JOGL on Debian</title>
        <link>https://mike42.me/blog/2014-09-how-to-install-jogl-on-debian</link>
        <pubDate>Mon, 22 Sep 2014 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2014-09-how-to-install-jogl-on-debian</guid>
        <description>&lt;p&gt;JOGL is an OpenGL binding for Java (&lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/Java_OpenGL&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;wiki&lt;/a&gt;) which wraps the C OpenGL API. On Debian-based systems, you might want to use the version from the package manager, and here is how to do so.&lt;/p&gt;
&lt;p&gt;First, install it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install libjogl2-java
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, you need these JAR files in your build path:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/usr/share/java/jogl2.jar
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/usr/share/java/gluegen2-rt.jar
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In Eclipse, this is achieved by clicking &lt;strong&gt;Project -&amp;gt; Properties -&amp;gt; Java Build Path -&amp;gt; Libraries -&amp;gt; Add External Jar&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;(If you don&amp;rsquo;t have &lt;code&gt;gluegen2-rt.jar&lt;/code&gt;, then you need to install the &lt;code&gt;libgluegen2-rt-java&lt;/code&gt; package as well).&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to generate professional-quality PDF files from PHP</title>
        <link>https://mike42.me/blog/2014-08-how-to-generate-professional-quality-pdf-files-from-php</link>
        <pubDate>Thu, 21 Aug 2014 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2014-08-how-to-generate-professional-quality-pdf-files-from-php</guid>
        <description>&lt;p&gt;There are a few ways to go about making PDF files from your PHP web app. Your options are basically:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Put all of your text in a &lt;a href=&#34;http://en.wikipedia.org/wiki/A4_paper#A_series&#34;&gt;210mm&lt;/a&gt; column and get the user to save it as PDF.&lt;/li&gt;&lt;/li&gt;
&lt;li&gt;Learn a purpose-built library, such as &lt;a href=&#34;http://php.net/manual/en/pdf.examples-basic.php&#34;&gt;FPDF&lt;/a&gt; (free) or &lt;a href=&#34;http://php.net/manual/en/book.pdf.php&#34;&gt;pdflib&lt;/a&gt; (proprietary).&lt;/li&gt;
&lt;li&gt;Use PHP for generating markup which can be saved to PDF. The markup I&amp;rsquo;m suggesting is of course &lt;a href=&#34;http://en.wikibooks.org/wiki/LaTeX&#34;&gt;LaTeX&lt;/a&gt;&lt;/li&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This article assumes an intermediate knowledge of both PHP and LaTeX, and that your server is running Linux.&lt;/p&gt;
&lt;h2 id=&#34;the-software-mix&#34;&gt;The software mix
&lt;/h2&gt;&lt;p&gt;PHP is an open-source server package which generates HTML pages, usually based on some sort of dynamic data. It is equally good at (but less well known for) generating other types of markup.&lt;/p&gt;
&lt;p&gt;LaTeX is an open source document typesetting system, which will take a markup file in &lt;code&gt;.tex&lt;/code&gt; format, and output a printable document, such as a PDF. The engine I will use here is &lt;a href=&#34;http://en.wikipedia.org/wiki/XeTeX&#34;&gt;XeLaTeX&lt;/a&gt;, because it supports modern trimmings such as Unicode and OpenType fonts.&lt;/p&gt;
&lt;p&gt;Naturally, this post will use PHP to populate a &lt;code&gt;.tex&lt;/code&gt; file, and then &lt;code&gt;xelatex&lt;/code&gt; to create a PDF for the user.&lt;/p&gt;
&lt;p&gt;This sounds straightforward enough, but it may not work with all shared hosts. Check your setup before you read on:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Your server needs PHP, with &lt;a href=&#34;http://php.net/manual/en/features.safe-mode.php&#34;&gt;safe mode&lt;/a&gt; disabled, so that it can run commands.&lt;/li&gt;
&lt;li&gt;This server needs &lt;code&gt;xelatex&lt;/code&gt;, or a suitable substitute such as &lt;code&gt;pdflatex&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;a-bit-about-markup&#34;&gt;A bit about markup
&lt;/h2&gt;&lt;p&gt;We will be working with &lt;code&gt;.tex&lt;/code&gt; templates, which will be valid LaTeX files. The basic rules are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Define a &lt;code&gt;\newcommand&lt;/code&gt; for every variable, so that you can compile the document without PHP.&lt;/li&gt;
&lt;li&gt;Drop PHP code in comments, which will print out code to override those variables.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So you will end up with code like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-latex&#34; data-lang=&#34;latex&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Make placeholders visible
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\newcommand&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\placeholder&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;[1]&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\textbf&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;$&lt;/span&gt; #1 &lt;span class=&#34;s&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Defaults for each variable
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\newcommand&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\test&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\placeholder&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Data here&lt;span class=&#34;nb&#34;&gt;}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Fill in
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% &amp;lt;?php echo &amp;#34;\n&amp;#34; . &amp;#34;\\renewcommand{\\test}{&amp;#34; . LatexTemplate::escape($data[&amp;#39;test&amp;#39;]) . &amp;#34;}\n&amp;#34;; ?&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Look messy? A multi-line block of PHP is a little easier to follow. This example is from the body of a table, see if you can figure out the syntax:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-latex&#34; data-lang=&#34;latex&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;%&amp;lt;?php                                                                      /*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% */ foreach($data[&amp;#39;invoiceItem&amp;#39;] as $invoiceItem) {                        /*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% */    echo &amp;#34;\n&amp;#34; . LatexTemplate::escape($invoiceItem[&amp;#39;item&amp;#39;]) . &amp;#34; &amp;amp; &amp;#34; .   /*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% */        LatexTemplate::escape($invoiceItem[&amp;#39;qty&amp;#39;]) . &amp;#34; &amp;amp; &amp;#34; .            /*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% */        LatexTemplate::escape($invoiceItem[&amp;#39;price&amp;#39;]) . &amp;#34; &amp;amp; &amp;#34; .          /*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% */        LatexTemplate::escape($invoiceItem[&amp;#39;total&amp;#39;]) . &amp;#34;\\\\\n&amp;#34;;        /*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% */ } ?&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So what about this &lt;code&gt;LatexTemplate::escape()&lt;/code&gt; business? In LaTeX, just about every symbol seems to be part of the syntax, so it is sadly not very simple to escape.&lt;/p&gt;
&lt;p&gt;I have settled on the following series of &lt;code&gt;str_replace()&lt;/code&gt; calls to sanitise information for display. It is crude but effective. Generating LaTex is much like generating SQL, HTML or LDIF from your website: it is quite important to make a habit of wrapping every piece of data with a function to prevent users from writing (&amp;lsquo;injecting&amp;rsquo;) arbitrary code into your document:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * Series of substitutions to sanitise text for use in LaTeX.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * http://stackoverflow.com/questions/2627135/how-do-i-sanitize-latex-input
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * Target document should \usepackage{textcomp}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;escape&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Prepare backslash/newline handling
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\\\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Rescue newlines
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;preg_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/[\x00-\x1F\x7F-\xFF]/&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Strip all non-printables
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\\\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Re-insert newlines and clear \\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\\\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Use double-backslash to signal a backslash in the input (escaped in the final step).
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Symbols which are used in LaTeX syntax
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;{&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;{&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;$&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;$&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;amp;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;amp;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;#&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;#&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;^&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;textasciicircum{}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;_&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;_&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;~&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;textasciitilde{}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;%&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;%&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Brackets &amp;amp; pipes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;lt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;textless{}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;textgreater{}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;|&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;textbar{}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Quotes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\&amp;#34;&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;textquotedbl{}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#39;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;textquotesingle{}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;`&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;textasciigrave{}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Clean up backslashes from before
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\\\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;textbackslash{}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Substitute backslashes from first step.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\\\&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;trim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Replace newlines (trim is in case of leading \\)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We then have a template which we can &lt;code&gt;include()&lt;/code&gt; from PHP, or run &lt;code&gt;xelatex&lt;/code&gt; over. Below is &lt;code&gt;minimal.tex&lt;/code&gt;, a minimal example of a PHP-latex template in this form:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-latex&#34; data-lang=&#34;latex&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% This file is a valid PHP file and also a valid LaTeX file
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% When processed with LaTeX, it will generate a blank template
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Loading with PHP will fill it with details
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\documentclass&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;article&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Required for proper escaping
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\usepackage&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;textcomp&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;c&#34;&gt;% Symbols
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\usepackage&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;[T1]&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;fontenc&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;c&#34;&gt;% Input format
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Because Unicode etc.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\usepackage&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;fontspec&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;c&#34;&gt;% For loading fonts
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\setmainfont&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Liberation Serif&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;c&#34;&gt;% Has a lot more symbols than Computer Modern
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Make placeholders visible
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\newcommand&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\placeholder&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;[1]&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\textbf&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;$&lt;/span&gt; #1 &lt;span class=&#34;s&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Defaults for each variable
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\newcommand&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\test&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;}{&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\placeholder&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Data here&lt;span class=&#34;nb&#34;&gt;}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% Fill in
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;% &amp;lt;?php echo &amp;#34;\n&amp;#34; . &amp;#34;\\renewcommand{\\test}{&amp;#34; . LatexTemplate::escape($data[&amp;#39;test&amp;#39;]) . &amp;#34;}\n&amp;#34;; ?&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\begin&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;document&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\section&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Data From PHP&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;\test&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\end&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;document&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;generate-a-pdf-on-the-server&#34;&gt;Generate a PDF on the server
&lt;/h2&gt;&lt;p&gt;Here is where the fun begins. There is no plugin for compiling a LaTeX document, so we need to directly execute the command on a file.&lt;/p&gt;
&lt;p&gt;Looks like we need to save the output somewhere then. You would generate your filled-in LaTeX code in a temporary file by doing something like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; * Generate a PDF file using xelatex and pass it to the user
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sd&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;download&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$template_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$outp_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Pre-flight checks
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;file_exists&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$template_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;throw&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Exception&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Could not open template&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$f&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;tempnam&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sys_get_temp_dir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;tex-&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;throw&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Exception&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Failed to create temporary file&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$tex_f&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$f&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;.tex&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$aux_f&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$f&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;.aux&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$log_f&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$f&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;.log&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$pdf_f&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$f&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;.pdf&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Perform substitution of variables
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;ob_start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;include&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$template_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;file_put_contents&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$tex_f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ob_get_clean&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The next step is to execute your engine of choice on the output files:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Run xelatex (Used because of native unicode and TTF font support)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nv&#34;&gt;$cmd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;xelatex -interaction nonstopmode -halt-on-error %s&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nx&#34;&gt;escapeshellarg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$tex_f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;chdir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sys_get_temp_dir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;exec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$cmd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$foo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once this is done, you can delete a lot of the extra LaTeX files, and check if a &lt;code&gt;.pdf&lt;/code&gt; appeared as expected:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// No need for these files anymore
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;unlink&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$tex_f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;unlink&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$aux_f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;unlink&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$log_f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Test here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;file_exists&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$pdf_f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;o&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;unlink&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;throw&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Exception&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Output was not generated and latex returned: &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$ret&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And of course, send the completed file back via HTTP:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Send through output
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nv&#34;&gt;$fp&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;fopen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$pdf_f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;rb&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Content-Type: application/pdf&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Content-Disposition: attachment; filename=&amp;#34;&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$outp_file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#34;&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Content-Length: &amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;filesize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$pdf_f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;fpassthru&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$fp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Final cleanup
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;unlink&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$pdf_f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;unlink&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The static functions &lt;code&gt;escape($text)&lt;/code&gt; and &lt;code&gt;download($data, $template_file, $outp_file)&lt;/code&gt; are together placed into a class called &lt;code&gt;LatexTemplate&lt;/code&gt; for the remainder of the example (&lt;a href=&#34;https://github.com/mike42/web-pdf/blob/master/LatexTemplate.php&#34;&gt;complete file on GitHub&lt;/a&gt;).&lt;/p&gt;
&lt;h2 id=&#34;putting-it-all-together&#34;&gt;Putting it all together
&lt;/h2&gt;&lt;p&gt;With the library and template, it is quite easy to set up a PHP script which triggers the above code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;require_once&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;../LatexTemplate.php&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$test&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;isset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$_GET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;t&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Make the LaTeX file and send it through
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nv&#34;&gt;$test&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$_GET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;t&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$test&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// Test pattern to show symbol handling
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;256&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nv&#34;&gt;$test&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;chr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34; . &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;try&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;LatexTemplate&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;download&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;test&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;minimal.tex&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;foobar.pdf&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;catch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Exception&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$e&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;getMessage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;?&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;head&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;title&amp;gt;LaTeX test (minimal)&amp;lt;/title&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;/head&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;/html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;body&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;    &amp;lt;p&amp;gt;Enter some text to be placed on the output:&amp;lt;/p&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;    &amp;lt;form&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;        &amp;lt;input type=&amp;#34;text&amp;#34; name=&amp;#34;t&amp;#34; /&amp;gt;&amp;lt;input type=&amp;#34;submit&amp;#34; value=&amp;#34;Generate&amp;#34; /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;    &amp;lt;/form&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;/body&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;/html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The above code will show a form, which asks for input. When it gets some text, it will generate a PDF containing the text. If no text is given, it will output an ASCII table, simply to show that it can handle the symbols.
Once the template code is hidden away, this powerful technique is easily applied.&lt;/p&gt;
&lt;h2 id=&#34;results&#34;&gt;Results
&lt;/h2&gt;&lt;p&gt;This is only a minimal example. In any real application, your template would be more extensive.&lt;/p&gt;
&lt;p&gt;Compiling the template directly creates &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2014-08-how-to-generate-professional-quality-pdf-files-from-php/2014-08-pdf-minimal.pdf&#34; &gt;this PDF&lt;/a&gt;, which marks out placeholders for fields which will be populated by the user:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-08-how-to-generate-professional-quality-pdf-files-from-php/2014-08-pdf-minimal.png&#34;
	width=&#34;595&#34;
	height=&#34;842&#34;
	srcset=&#34;https://mike42.me/blog/2014-08-how-to-generate-professional-quality-pdf-files-from-php/2014-08-pdf-minimal_hu_1131f286a45fb806.png 480w, https://mike42.me/blog/2014-08-how-to-generate-professional-quality-pdf-files-from-php/2014-08-pdf-minimal_hu_fb03260a30e5434f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;70&#34;
		data-flex-basis=&#34;169px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;From the web, a form is presented to fill this single field:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-08-how-to-generate-professional-quality-pdf-files-from-php/2014-08-pdf-form.png&#34;
	width=&#34;612&#34;
	height=&#34;383&#34;
	srcset=&#34;https://mike42.me/blog/2014-08-how-to-generate-professional-quality-pdf-files-from-php/2014-08-pdf-form_hu_99c76b5426cd72bb.png 480w, https://mike42.me/blog/2014-08-how-to-generate-professional-quality-pdf-files-from-php/2014-08-pdf-form_hu_87dbabb93ea41ae3.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;159&#34;
		data-flex-basis=&#34;383px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Which results in &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2014-08-how-to-generate-professional-quality-pdf-files-from-php/2014-08-pdf-foobar.pdf&#34; &gt;this PDF&lt;/a&gt; containing the user data:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-08-how-to-generate-professional-quality-pdf-files-from-php/2014-08-pdf-foobar.png&#34;
	width=&#34;595&#34;
	height=&#34;842&#34;
	srcset=&#34;https://mike42.me/blog/2014-08-how-to-generate-professional-quality-pdf-files-from-php/2014-08-pdf-foobar_hu_ea4a5875ddbc19e8.png 480w, https://mike42.me/blog/2014-08-how-to-generate-professional-quality-pdf-files-from-php/2014-08-pdf-foobar_hu_ffa3be799246c731.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;70&#34;
		data-flex-basis=&#34;169px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;tips&#34;&gt;Tips
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;The text after &lt;code&gt;\end{document}&lt;/code&gt; is not even parsed in latex. Use this area to write &lt;code&gt;&amp;lt;?php ?&amp;gt;&lt;/code&gt; with
fewer constraints.&lt;/li&gt;
&lt;li&gt;Consult &lt;a href=&#34;https://github.com/mike42/web-pdf&#34;&gt;the github repository for this code&lt;/a&gt; to see the complete example.&lt;/li&gt;
&lt;li&gt;Comment out the line &lt;code&gt;@unlink($tex_f);&lt;/code&gt; of you want to preserve (for debugging, etc) the generated markup.&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>How to query Microsoft SQL Server from PHP</title>
        <link>https://mike42.me/blog/2014-06-how-to-query-microsoft-sql-server-from-php</link>
        <pubDate>Tue, 10 Jun 2014 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2014-06-how-to-query-microsoft-sql-server-from-php</guid>
        <description>&lt;p&gt;This post is for anybody who runs a GNU/Linux server and needs to query a MSSQL database. This setup will work on Debian and its relatives. As it&amp;rsquo;s a dense mix of technologies, so I&amp;rsquo;ve included all of the details which worked for me.&lt;/p&gt;
&lt;p&gt;An obvious note: Microsoft SQL is not an ideal choice of database to pair with a GNU/Linux server, but may be acceptable if you are writing something which needs to import some data from external application which has a better reason to be using it.&lt;/p&gt;
&lt;p&gt;A command-line alternative to this setup would be  &lt;code&gt;sqsh&lt;/code&gt;, which will let you running scheduled queries without PHP, if that&amp;rsquo;s what you&amp;rsquo;re after.&lt;/p&gt;
&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites
&lt;/h2&gt;&lt;p&gt;Once you have PHP, the required libraries can be fetched with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install unixodbc php5-odbc tdsodbc
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;MSSQL is accessed with the FreeTDS driver. Once the above packages are installed, you need to tell ODBC where to find this driver, by adding the following block to &lt;code&gt;/etc/odbcinst.ini&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;[FreeTDS]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;Description&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;MSSQL DB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;Driver&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;/usr/lib/x86_64-linux-gnu/odbc/libtdsodbc.so&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;UsageCount&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The path is different on platforms other than &lt;code&gt;amd64&lt;/code&gt;. Check the file list for the &lt;a class=&#34;link&#34; href=&#34;https://packages.debian.org/search?keywords=tdsodbc&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;tdsodbc package&lt;/a&gt; on your architecture if you lose track of the path.&lt;/p&gt;
&lt;p&gt;The next step requires that you know the database server address, version, and database name. Add a block for your database to the end of `/etc/odbc.ini`:
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;[foodb]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;Driver&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;FreeTDS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;Description&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;Foo Database&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;Trace&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;Yes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;TraceFile&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/tmp/sql.log&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;ForceTrace&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;yes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;Server&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;10.x.x.x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;Port&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;1433&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;Database&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;FooDB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;TDS_Version&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;8.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Experiment with &lt;code&gt;TDS_Version&lt;/code&gt; values if you have issues connecting. Different versions of MSSQL require different values. The name of the data source (&amp;lsquo;foodb&amp;rsquo;), the &lt;code&gt;Database&lt;/code&gt;, &lt;code&gt;Description&lt;/code&gt; and &lt;code&gt;Server&lt;/code&gt; are all bogus values which you will need to fill.&lt;/p&gt;
&lt;h2 id=&#34;an-example&#34;&gt;An example
&lt;/h2&gt;&lt;p&gt;For new PHP scripts, database queries are invariably performed via &lt;a class=&#34;link&#34; href=&#34;http://www.php.net/manual/en/book.pdo.php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;PHP Data Objects (PDO)&lt;/a&gt;. The good news is, it is easy to use it with MSSQL with PDO.&lt;/p&gt;
&lt;p&gt;The below file takes a query on standard input, throws it at the database, and returns the result as comma-separated values.&lt;/p&gt;
&lt;p&gt;Save this as &lt;code&gt;query.php&lt;/code&gt; and fill in your data source (&amp;lsquo;odbc:foodb&amp;rsquo; here), username, and password.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#!/usr/bin/env php
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$query&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;file_get_contents&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;php://stdin&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$user&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;baz;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;$pass = &amp;#39;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;super&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;secret&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;password&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;here&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;$dbh = new PDO(&amp;#39;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;odbc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;foodb&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$pass&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$dbh&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setAttribute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;PDO&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;ATTR_ERRMODE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;PDO&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;ERRMODE_EXCEPTION&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$sth&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$dbh&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;prepare&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$query&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$sth&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;execute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$results&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$sth&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;fetchAll&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;PDO&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;FETCH_ASSOC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Quick exit if there are no rows */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$results&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$f&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;fopen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;php://stdout&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;w&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Output header */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$results&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$header&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;foreach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$a&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$key&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;fputcsv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Output rows */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;foreach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$results&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;fputcsv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;fclose&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To test the new script, first make it executable:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chmod +x query.php
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To run a simple test query:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;echo &amp;#34;SELECT Name from sys.tables ORDER BY Name;&amp;#34; | ./query.php
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;refining-the-setup&#34;&gt;Refining the setup
&lt;/h2&gt;&lt;p&gt;The above script has some cool features: It&amp;rsquo;s short, actually useful, and it sets  &lt;code&gt;PDO::ERRMODE_EXCEPTION&lt;/code&gt;. This means that if something breaks, it will fail loudly and tell you why.
Hopefully, if your setup has issues, you can track down the cause with the error, and solve it by scrolling through this how-to again.&lt;/p&gt;
&lt;p&gt;If you encounter a MSSQL database with an unknown schema, then you may want to list all rows and columns. This is achieved with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;SELECT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tables&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;AS&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tbl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;columns&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;AS&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;col&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;FROM&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sys&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;columns&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;JOIN&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sys&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tables&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ON&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;columns&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;object_id&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tables&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;object_id&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ORDER&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;BY&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tbl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;col&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;the-catch&#34;&gt;The catch
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;ve run into some bizarre limitations using this. Be sure to run it on a server which you can update at the drop of a hat.&lt;/p&gt;
&lt;p&gt;A mini-list of issues I&amp;rsquo;ve seen with this combination of software (no sources as I never tracked down the causes):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An old version of the driver would segfault PHP, apparently when non-ASCII content appeared in a text field.&lt;/li&gt;
&lt;li&gt;Substituting non-text values fails in the version I am using, although Google suggests that updating the ODBC driver fixes this.&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>A Yes/No filtering tool for images</title>
        <link>https://mike42.me/blog/2014-06-a-yesno-filtering-tool-for-images</link>
        <pubDate>Mon, 09 Jun 2014 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2014-06-a-yesno-filtering-tool-for-images</guid>
        <description>&lt;p&gt;While collecting &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2014-01-scripted-screen-captures&#34; &gt;large numbers&lt;/a&gt; of screen captures for writing documentation, I noticed that it takes far too long to filter out the junk.&lt;/p&gt;
&lt;p&gt;To fix this, I coded up &lt;code&gt;yn&lt;/code&gt; (source code at &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/yn&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/yn&lt;/a&gt; on GitHub). Given a list of images, it will display each one to the user, which they then include by pressing Y (yes) or exclude by pressing N (no) (hence the name &lt;code&gt;yn&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The images which are selected are saved as a list, so that a script can continue by processing them in some way. This could be by copying them elsewhere, or generating a document with spaces to caption them. The &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/yn/blob/master/README.md&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;example in the README.md&lt;/a&gt; does both of these.&lt;/p&gt;
&lt;p&gt;The code to this early version is very simple, which makes it a good example of a simple OpenCV C++ app. I&amp;rsquo;ve stepped through it below.&lt;/p&gt;
&lt;h2 id=&#34;the-code&#34;&gt;The code
&lt;/h2&gt;&lt;p&gt;C++ does console input and output via the &lt;code&gt;iostream&lt;/code&gt; library:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To use OpenCV with a GUI, you need these headers. You then need to add them to your include path, and link to OpenCV for the program to compile:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;cv.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;highgui.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This line simly tells the compiler that when we say &lt;code&gt;cout&lt;/code&gt; (&lt;b&gt;c&lt;/b&gt;onsole &lt;b&gt;out&lt;/b&gt;), we mean &lt;code&gt;std::cout&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;using&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;namespace&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The only OpenCV code is in the below function. The steps are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;load an image from a file via &lt;code&gt;imread()&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;display it in a window with &lt;code&gt;imshow()&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;capture the next keypress with &lt;code&gt;waitKey()&lt;/code&gt;, then&lt;/li&gt;
&lt;li&gt;delete the window with &lt;code&gt;destroyWindow()&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * Load a file, and wait for the user to press a key.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * If the pressed key is &amp;#39;y&amp;#39;, print the filename.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;yn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;cv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Mat&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;img&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;img&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;imread&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;img&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;cerr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Failed to load &amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fn&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;endl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;cv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;namedWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;cv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;imshow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;img&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;waitKey&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;cv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;destroyWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;sc&#34;&gt;&amp;#39;y&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;cout&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fn&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;endl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// &amp;#39;y&amp;#39; pressed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0x1B&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// ESC pressed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So with that library usage out of the way, all we need to do is get the list of files to check, and stop popping up windows when the user has pressed the escape key.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * Get list of files from command-line arguments and display them in turn
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;**&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Command-line arguments given */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;yn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;cerr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Quitting.&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;next&#34;&gt;Next
&lt;/h2&gt;&lt;p&gt;The delay between each image appearing could be removed by loading them in a separate thread, which I may do in a future version.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Crash course: Run Windows on desktop Linux</title>
        <link>https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux</link>
        <pubDate>Mon, 09 Jun 2014 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux</guid>
        <description>&lt;p&gt;Sometimes, you need to use a tricky windows-only program on a Linux desktop. If you have a Windows install disk and licence at your disposal, then this post will show you how to get a Windows environment running without dual-booting.&lt;/p&gt;
&lt;p&gt;The host here is a Debian box, and the guest is running Windows 7. The instructions will work with slight modifications for any mix of Linux and Windows&lt;/p&gt;
&lt;p&gt;On the desktop, some things are not as important as the server world. Some things are excluded for simplicity: network bridging, para-virtualised disks, migration between hosts, and disk replication.&lt;/p&gt;
&lt;h2 id=&#34;software-setup&#34;&gt;Software setup
&lt;/h2&gt;&lt;p&gt;Everything required from the host machine can be pulled in via Debian&amp;rsquo;s &lt;code&gt;qemu-kvm&lt;/code&gt; package.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install qemu-kvm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;virtual-machine-setup&#34;&gt;Virtual machine setup
&lt;/h2&gt;&lt;p&gt;Prepare a disk image for Windows. The &lt;code&gt;qcow2&lt;/code&gt; format is suggested for the desktop as it will not expand the file to the full size until the guest uses the space:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qemu-img create -f qcow2 windows.img 30G
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Launch the Windows installer in KVM with a command that looks something like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kvm -hda windows.img --cdrom windows-install-disc.iso -vga std -localtime -net nic,model=ne2k_pci -m 2048
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note the &lt;code&gt;-m&lt;/code&gt; option is the number of megabytes of RAM to allocate. You can set it a little lower if you don&amp;rsquo;t have much to spare, but if it&amp;rsquo;s too low you&amp;rsquo;ll get this screen:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-noboot.png&#34;
	width=&#34;1024&#34;
	height=&#34;768&#34;
	srcset=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-noboot_hu_43e7b1caa4fdeeee.png 480w, https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-noboot_hu_d3606353f9b052a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;If you have a physical disk but no &lt;code&gt;.iso&lt;/code&gt; of it, then using the disk drive via &lt;code&gt;--cdrom /dev/cdrom&lt;/code&gt; will work.&lt;/p&gt;
&lt;h2 id=&#34;windows-installer&#34;&gt;Windows installer
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;ve included a walkthrough here of what the Windows 7 installer will prompt for, since it does work a bit differently to a typical Linux installer.&lt;/p&gt;
&lt;p&gt;Select language, accept the licence agreement, choose the target disk, and let the files copy:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-005.png&#34;
	width=&#34;1024&#34;
	height=&#34;768&#34;
	srcset=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-005_hu_3b3a35e25547ac52.png 480w, https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-005_hu_69943e997a33faa9.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-023.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-023_hu_7aa63f0df052323f.png 480w, https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-023_hu_38e4d69a38b5737a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-024.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-024_hu_61e0ed9312ae89da.png 480w, https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-024_hu_f15e97bb5d9a026f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-028.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-028_hu_ebf5e130cf7f17a9.png 480w, https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-028_hu_c2f108556b020bee.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-033.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-033_hu_5a64f9acc2f394c1.png 480w, https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-033_hu_e66ea95d694090ee.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-035.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-035_hu_b0f5fe38834a5a99.png 480w, https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-035_hu_37d7ef9e7c950f05.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-081.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-081_hu_94fecce86b026275.png 480w, https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-081_hu_fa620dcd37955a17.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-149.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-149_hu_41bafebe3881e046.png 480w, https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-149_hu_a99c45303b4ae545.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;After reboot, enter the user details, licence key, update settings and timezone:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-160.png&#34;
	width=&#34;1024&#34;
	height=&#34;768&#34;
	srcset=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-160_hu_288f476792287e73.png 480w, https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-160_hu_55edfb2e0e3adbd8.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-178.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-178_hu_476d44a135c509d5.png 480w, https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-178_hu_8194c8ba4708fade.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-190.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-190_hu_2a40f70966a02573.png 480w, https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-190_hu_23b90b9366c0c0d.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-191.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-191_hu_870796b1809f03a3.png 480w, https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-191_hu_ac1b2b695fc09d3a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-199.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-199_hu_7022b04ae6924566.png 480w, https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-199_hu_30273408b1477743.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-205.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-205_hu_d80cd26ecba6a521.png 480w, https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-205_hu_16c6953551a84e3d.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-214.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-214_hu_148c2bab00dcf79.png 480w, https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-214_hu_6956af14864a8c33.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-250.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-250_hu_80e6402f36b0a6f.png 480w, https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-250_hu_b3082af39e07252a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-254.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-254_hu_52023be04c936fc0.png 480w, https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-254_hu_602b1408b5e3fc84.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-261.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-261_hu_348c8ad3dc2d3e17.png 480w, https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-261_hu_16bcc9450d4616f8.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;After another reboot, Windows is installed in the virtual machine:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-263.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-263_hu_695f668f6113ef36.png 480w, https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-263_hu_e30b6cb43df6ef5f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-265.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-265_hu_f98184148ca52ab8.png 480w, https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-265_hu_7ed344d0c50d1004.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-277.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-277_hu_42aac35d6471b81a.png 480w, https://mike42.me/blog/2014-06-crash-course-run-windows-on-desktop-linux/2014-06-04-capture-277_hu_169d176fa3b3fe94.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;post-install-tasks&#34;&gt;Post-install tasks
&lt;/h2&gt;&lt;p&gt;The guest you have now will only run at standard VGA resolutions, and will probably not be networked. This section will show you how to fix that.&lt;/p&gt;
&lt;h3 id=&#34;network-drivers&#34;&gt;Network drivers
&lt;/h3&gt;&lt;p&gt;You will notice that we are launching the guest with &lt;code&gt;-net nic,model=virtio&lt;/code&gt;. This means that we are using a virtual network card, rather than simulating a real one. You need to fetch a disk image with the latest binary drivers, which are best tracked down on linux-kvm.org &lt;a class=&#34;link&#34; href=&#34;https://www.google.com.au/search?q=virtio%20binary%20drivers%20for%20windows%20guest&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;via google&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once you have the disk image in the same folder as your virtual machine, shut down and launch it with a CD:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kvm -hda windows.img --cdrom virtio-win-0.1-74.iso -vga std -localtime -net nic,model=ne2k_pci -m 2048
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Under &amp;ldquo;My Computer&amp;rdquo; track down the &amp;ldquo;Device Manager&amp;rdquo;, find your network card, and tell Windows to update the drivers. You can then point it to the CDROM&amp;rsquo;s &amp;ldquo;Win7&amp;rdquo; directory (or other one, if you are installing a different guest). After the network adapter is recognised, you will be connected automatically.&lt;/p&gt;
&lt;p&gt;Note that you are using &amp;ldquo;user-mode&amp;rdquo; networking, which means you are on a simulated subnet, and can only communicate via TCP and UDP (ie, &lt;code&gt;ping&lt;/code&gt; will not work). This can be a little slow, but will work on a laptop host whether plugged in or running on Wi-Fi.&lt;/p&gt;
&lt;h3 id=&#34;remote-desktop&#34;&gt;Remote desktop
&lt;/h3&gt;&lt;p&gt;The screen resolution and mouse sensitivity on the VM console is unlikely to match your host computer. The best way around this is not to fix with settings and drivers, but to enable remote desktop and log in via the network. This lets you use an arbitrary screen size, and match mouse speed to the host.&lt;/p&gt;
&lt;p&gt;When run on localhost, so it is neigher laggy nor a security issue, and makes it possible to leverage all RDP features.&lt;/p&gt;
&lt;p&gt;First, in the guest, enable remote desktop using &lt;a class=&#34;link&#34; href=&#34;http://technet.microsoft.com/en-us/magazine/ff404238.aspx&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;these Microsoft instructions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Then shut down and boot up with the extra &lt;code&gt;-redir tcp:3389::3389&lt;/code&gt; option:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kvm -hda windows.img -vga std -localtime -net nic,model=ne2k_pci -m 2048 -redir tcp:3389::3389
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On the host, wait for the guest to boot, then use &lt;code&gt;rdesktop&lt;/code&gt; to log in:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rdestkop localhost
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One this works, you can shut down and boot with the extra &lt;code&gt;-nographic&lt;/code&gt; option to leave remote desktop as the only way to interact with the guest:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kvm -hda windows.img -vga std -localtime -net nic,model=ne2k_pci -m 2048 -nographic -redir tcp:3389::3389
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;rdesktop&lt;/code&gt; tool supports sound, file and printer redirection. It can also run fullscreen when launched with &lt;code&gt;-f&lt;/code&gt;. All the details are in &lt;code&gt;man rdesktop&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If you end up using the guest operating system more, it is worth investigating USB-redirection for any peripherals (printers or mobile phones), running a virtual sound card, or running SAMBA on the host to share files.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Including git commit history in a LaTeX document</title>
        <link>https://mike42.me/blog/2014-04-including-git-commit-history-in-a-latex-document</link>
        <pubDate>Sun, 27 Apr 2014 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2014-04-including-git-commit-history-in-a-latex-document</guid>
        <description>&lt;p&gt;LaTeX is a document typesetting system. It allows you to mark up a document as a plain text file, so lends itself well to being used within a source-code management program such as git. I found a need to include a changelog in a document, and found &lt;a class=&#34;link&#34; href=&#34;https://coderwall.com/p/5cv5lg&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this brilliant blog article&lt;/a&gt; by Jerel Unruh which creates a HTML log using &lt;a class=&#34;link&#34; href=&#34;http://git-scm.com/docs/git-log&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;git log&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For inclusion within a Makefile target, I re-worked this into a shell script, &lt;strong&gt;changes.sh&lt;/strong&gt;, which will also auto-detect URL&amp;rsquo;s for any Github-hosted repository:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# Find remote URL for hashes (designed for GitHub-hosted projects)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;origin&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;git config remote.origin.url&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;base&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;dirname &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$origin&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;/&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;basename &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$origin&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; .git&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Output LaTeX table in chronological order&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;\\begin{tabular}{l l l}\\textbf{Detail} &amp;amp; \\textbf{Author} &amp;amp; \\textbf{Description}\\\\\\hline&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git log --pretty&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;format:&lt;span class=&#34;s2&#34;&gt;&amp;#34;\\href{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$base&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/commit/%H}{%h} &amp;amp; %an &amp;amp; %s\\\\\\hline&amp;#34;&lt;/span&gt; --reverse
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;\end{tabular}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The above script outputs a LaTeX table, including a hyperlink to each commit. In the pre-amble, you need:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;\usepackage{hyperref}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In your Makefile, you might add something like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;changelog:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	./changes.sh &amp;gt; changelog.tex
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The resulting changelog can then be included in the document via:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;\input{changelog.tex}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>QJoyPad update</title>
        <link>https://mike42.me/blog/2014-04-qjoypad-update</link>
        <pubDate>Sun, 27 Apr 2014 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2014-04-qjoypad-update</guid>
        <description>&lt;p&gt;As of April, there is now a &lt;code&gt;qjoypad&lt;/code&gt; package available in the official Debian repository, see &lt;a class=&#34;link&#34; href=&#34;https://packages.debian.org/unstable/main/qjoypad&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://packages.debian.org/unstable/main/qjoypad&lt;/a&gt;. This program allows you to map joystick events to keyboard and mouse actions. This means that you could use, for example, a USB gamepad to browse the web.&lt;/p&gt;
&lt;p&gt;I have &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2013-06-qjoypad-coolness&#34; &gt;previously blogged about&lt;/a&gt; the lack of usable, packaged programs to do this, and highly recommend getting your hands on a USB gamepad and giving this a try. Depending on your distribution, you will soon be able to just run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install qjoypad
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then connect the gamepad and type:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qjoypad
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You then get a window which shows you which buttons you can map:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-04-qjoypad-update/2013-06-07-qjoypad.png&#34;
	width=&#34;387&#34;
	height=&#34;420&#34;
	srcset=&#34;https://mike42.me/blog/2014-04-qjoypad-update/2013-06-07-qjoypad_hu_2a19b736e7d485f3.png 480w, https://mike42.me/blog/2014-04-qjoypad-update/2013-06-07-qjoypad_hu_b6b2f32aeeda89d2.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;92&#34;
		data-flex-basis=&#34;221px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Clicking a button prompts you to press a key on your keyboard or select a mouse button, and each profile can be saved and named for later use.&lt;/p&gt;
&lt;p&gt;As far as small utility programs go, I now rely on this about as much as the Gnome calculator.&lt;/p&gt;
&lt;h2 id=&#34;an-alternative-antimicro&#34;&gt;An alternative: AntiMicro
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;ll also give a mention to &lt;a class=&#34;link&#34; href=&#34;http://ryochan7.com/projects/antimicro/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;AntiMicro&lt;/a&gt;, which has similar goals, and looks very promising.&lt;/p&gt;
&lt;p&gt;As a bit of background, there is a limitation in QJoyPad around adding modifier keys: For example, you simply can&amp;rsquo;t map a joystick button to &lt;code&gt;&amp;lt;Ctrl&amp;gt;+Q&lt;/code&gt;, making it tricky to use with most applications. The author of AntiMicro, &lt;a class=&#34;link&#34; href=&#34;https://github.com/Ryochan7&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Travis&lt;/a&gt;, sent me an email back in September to point out that his program both solves this issue, and has a Debian package available for download.&lt;/p&gt;
&lt;p&gt;Whilst I was quite impressed with the functionality in AntiMicro, I found it a lot more complex to set up. I think this would be more useful for gamers, as mouse acceleration and key repeats are overkill for my use case (browsing the web and controlling VLC, MythTV, etc).&lt;/p&gt;
&lt;p&gt;So, if you are a power user, then I suggest you give it a shot. Power users with &lt;code&gt;apt-get&lt;/code&gt; may also consider &lt;code&gt;joy2key&lt;/code&gt;, which is the best non-GUI tool for this, and is available in the Debian repositories.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Winning 2048 game with key-mashing?</title>
        <link>https://mike42.me/blog/2014-03-winning-2048-game-with-key-mashing</link>
        <pubDate>Mon, 24 Mar 2014 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2014-03-winning-2048-game-with-key-mashing</guid>
        <description>&lt;p&gt;This new, simple, addictive game is out, called &lt;a class=&#34;link&#34; href=&#34;http://http://gabrielecirulli.github.io/2048/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;2048&lt;/a&gt;. You need to slide two numbers together, resulting in a bigger number, in ever-increasing powers of two. You get 2048, and you win.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-03-winning-2048-game-with-key-mashing/2014-03-2048-1.png&#34;
	width=&#34;598&#34;
	height=&#34;726&#34;
	srcset=&#34;https://mike42.me/blog/2014-03-winning-2048-game-with-key-mashing/2014-03-2048-1_hu_4c6d7dec0f2c5c01.png 480w, https://mike42.me/blog/2014-03-winning-2048-game-with-key-mashing/2014-03-2048-1_hu_85b0fc49175b3d78.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;82&#34;
		data-flex-basis=&#34;197px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I noticed that somebody already wrote &lt;a class=&#34;link&#34; href=&#34;http://ov3y.github.io/2048-AI/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;neat AI&lt;/a&gt; for it, although it does run quite slowly. But then I also noticed a friend mashing keys in a simple pattern, and thought I should test whether this was more effective. The answer: it kinda is.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-03-winning-2048-game-with-key-mashing/2014-03-2048-2.png&#34;
	width=&#34;350&#34;
	height=&#34;531&#34;
	srcset=&#34;https://mike42.me/blog/2014-03-winning-2048-game-with-key-mashing/2014-03-2048-2_hu_7290defe502f512f.png 480w, https://mike42.me/blog/2014-03-winning-2048-game-with-key-mashing/2014-03-2048-2_hu_fa4015ddbd4e169f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;65&#34;
		data-flex-basis=&#34;158px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;At least in the first half of the game, a simple key-mashing pattern is a much faster way to build high numbers. The PHP script below will usually get to 512 without much trouble, but rarely to 1024. I would suggest running it for a while, and then taking over with some strategy.&lt;/p&gt;
&lt;h2 id=&#34;the-script&#34;&gt;The script
&lt;/h2&gt;&lt;p&gt;This script produces commands which can be piped to &lt;code&gt;xte&lt;/code&gt; for some automatic key-mashing on GNU / Linux. Save as &lt;code&gt;2048.php&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#!/usr/bin/env php
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;mouseclick&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;move&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Left&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;move&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Right&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;while&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;move&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Down&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;move&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Left&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;move&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Down&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;move&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Right&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;move&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$dir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;key &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$dir\nsleep&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; 0.025&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nx&#34;&gt;usleep&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;25000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And then in a terminal, run this then click over to a 2048 game:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sleep 3; php 2048.php | xte
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I hope this helps somebody to beat this game!&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Importing myki data into GnuCash</title>
        <link>https://mike42.me/blog/2014-03-importing-myki-data-into-gnucash</link>
        <pubDate>Wed, 05 Mar 2014 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2014-03-importing-myki-data-into-gnucash</guid>
        <description>&lt;p&gt;GnuCash, despite &lt;a class=&#34;link&#34; href=&#34;https://bugs.gnucash.org/buglist.cgi?bug_status=__open__&amp;amp;no_redirect=1&amp;amp;order=Importance&amp;amp;product=GnuCash&amp;amp;query_format=specific&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;all its bugs&lt;/a&gt;, is one of the best open source accounting programs going around.&lt;/p&gt;
&lt;p&gt;Since it is not hard to &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2013-09-how-to-liberate-your-myki-data&#34; &gt;export the history from a myki (public transport) card&lt;/a&gt;, I figured that it would be nice to track it as an account in GnuCash.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-03-importing-myki-data-into-gnucash/2014-03-myki-to-gnucash.png&#34;
	width=&#34;281&#34;
	height=&#34;105&#34;
	srcset=&#34;https://mike42.me/blog/2014-03-importing-myki-data-into-gnucash/2014-03-myki-to-gnucash_hu_dac1c326fcbda8a4.png 480w, https://mike42.me/blog/2014-03-importing-myki-data-into-gnucash/2014-03-myki-to-gnucash_hu_43971a4e0ee9b7b9.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;267&#34;
		data-flex-basis=&#34;642px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;transforming-the-data&#34;&gt;Transforming the data
&lt;/h2&gt;&lt;p&gt;The data on the statements is not quite suitable for an accounting program. Some changes that need to be done are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Conversion of date format to YYYY-MM-DD.&lt;/li&gt;
&lt;li&gt;Single-field descriptions for each transaction (&amp;ldquo;Top up myki money&amp;rdquo;, &amp;ldquo;Travel zone 2&amp;rdquo;), rather than multiple fields.&lt;/li&gt;
&lt;li&gt;Entries which have a 0.00 cost need to be removed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once you have a CSV of your data, the script below will filter it to be ready for import:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#!/usr/bin/env php
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Dump Myki CSV file to a file suitable for gnucash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;    (c) Michael Billington &amp;lt; michael.billington@gmail.com &amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;    MIT Licence */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$in&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;fopen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;php://stdin&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$out&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;fopen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;php://stdout&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;w&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;fopen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;php://stdout&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;w&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$lc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;while&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$line&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;fgets&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$in&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$lc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_getcsv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#34;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$date&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;implode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;array_reverse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;explode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;substr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;strpos&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$credit&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$credit&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Probably a top-up or reimbursement
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;            &lt;span class=&#34;nv&#34;&gt;$description&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Probably buying myki pass
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;            &lt;span class=&#34;nv&#34;&gt;$description&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;trim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Probably travel charges
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;            &lt;span class=&#34;nv&#34;&gt;$description&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Travel: &amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;, Zone &amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$debit&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$balance&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$balance&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Ignore non-charge entries
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;            &lt;span class=&#34;nx&#34;&gt;fputcsv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$out&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$description&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$credit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$debit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$balance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;fclose&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$in&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;fclose&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$out&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;fclose&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;why-would-you-track-it-as-an-account&#34;&gt;Why would you track it as an account?
&lt;/h2&gt;&lt;p&gt;Here are a few of reasons why a public transport card is account-like enough to put into GnuCash:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Money is not spent until you touch on and off — note that no GST is payable until the card balance is used. This means that if you record a top-up under Expenses, it&amp;rsquo;s not quite correct.&lt;/li&gt;
&lt;li&gt;You can cancel a myki and have its balance moved to another card.&lt;/li&gt;
&lt;li&gt;A card can be handed in, and the balance paid back to you as cash.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Update 2014-05-04:&lt;/strong&gt; All of these myki-related scripts are now available at &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/myki-import&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mike42/myki-import&lt;/a&gt; on GitHub.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Successful migration to WordPress in 3 easy steps</title>
        <link>https://mike42.me/blog/2014-03-successful-migration-to-wordpress-in-3-easy-steps</link>
        <pubDate>Mon, 03 Mar 2014 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2014-03-successful-migration-to-wordpress-in-3-easy-steps</guid>
        <description>&lt;p&gt;I made the decision in January to migrate this website to a WordPress installation, which is the CMS of choice for most blogs.&lt;/p&gt;
&lt;p&gt;This posed a big challenge, mainly because I had been using our in-house CMS to publish content for the past 2 years, meaning the content was tied up in a difficult-to-export format.&lt;/p&gt;
&lt;p&gt;Still, it allowed me to dig into the far more well-developed world of WordPress. My formula for a WordPress migration, in a nutshell:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Export your old blog as something WordPress can understand.&lt;/li&gt;
&lt;li&gt;Hack at the theme until your site is beautiful.&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t break your URLs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;export-your-blog&#34;&gt;Export your blog
&lt;/h2&gt;&lt;p&gt;Depending on how you are blogging already, you may be able to save an export which can be loaded into WordPress with a plugin (see &lt;a class=&#34;link&#34; href=&#34;https://codex.wordpress.org/Importing_Content&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Importing Content&lt;/a&gt; on the WordPress wiki).&lt;/p&gt;
&lt;p&gt;My old site was not in this lucky category, so I delved into the WXR (WordPress eXtended RSS) format. This &lt;a class=&#34;link&#34; href=&#34;https://code.google.com/p/google-blog-converters-appengine/source/browse/trunk/samples/wordpress-sample.wxr&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;example&lt;/a&gt; file was a big help, and I wrote up a short PHP script to create a similar-looking file from my blog.&lt;/p&gt;
&lt;h2 id=&#34;hack-at-the-theme&#34;&gt;Hack at the theme
&lt;/h2&gt;&lt;p&gt;I adapted the site from the &lt;a class=&#34;link&#34; href=&#34;http://evil.che.lu/projects/skittlish&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;&amp;lsquo;Skittlish&amp;rsquo;&lt;/a&gt; theme, which has also been ported to WordPress. Every theme carries some baggage, so I highly suggest rolling up your sleeves and opening &lt;code&gt;wp-content/themes&lt;/code&gt; on your blog.&lt;/p&gt;
&lt;p&gt;All non-feature modifications are done in WordPress via themes, so keep tweaking it until you&amp;rsquo;re happy, or get a designer to put together a theme that suits your needs.&lt;/p&gt;
&lt;h2 id=&#34;dont-break-your-urls&#34;&gt;Don&amp;rsquo;t break your URLs
&lt;/h2&gt;&lt;p&gt;I link between blog posts a lot, and breaking these links would leave a huge backlog of things to fix later (not to mention being an SEO sin). Using the import method above, I used article titles which matched the old permalinks.&lt;/p&gt;
&lt;p&gt;WordPress then lets you &lt;a class=&#34;link&#34; href=&#34;http://codex.wordpress.org/Using_Permalinks&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;configure permalinks&lt;/a&gt; to use this field, replicating the old behavior and keeping the links unmodified.&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap-up
&lt;/h2&gt;&lt;p&gt;If you run WordPress on your site, then it makes sense to have somebody on your team who really knows how it works.&lt;/p&gt;
&lt;p&gt;If your initial setup is not handled with care, then you could end up spending several days of work checking old content for errors.&lt;/p&gt;
&lt;p&gt;Good luck!&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Rolling your own cloud storage with Unison</title>
        <link>https://mike42.me/blog/2014-02-rolling-your-own-cloud-storage-with-unison</link>
        <pubDate>Sun, 23 Feb 2014 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2014-02-rolling-your-own-cloud-storage-with-unison</guid>
        <description>&lt;p&gt;Cloud storage is a very cool way to back up files, but it has two major drawbacks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If you back up everything, it will cost you a lot for the space.&lt;/li&gt;
&lt;li&gt;You need to trust that the company won&amp;rsquo;t lose, tamper with, or share your files.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I&amp;rsquo;ve recently discovered a tool called &lt;a class=&#34;link&#34; href=&#34;http://www.cis.upenn.edu/~bcpierce/unison/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Unison&lt;/a&gt;, which provides a bandwidth-efficient way to synchronise folders on two computers, solving both of those problems. It has clients for just about every platform, it&amp;rsquo;s open source, and it&amp;rsquo;s been around for over a decade.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve set up a copy of my laptop&amp;rsquo;s home directory on my desktop computer, so if the data is ever lost, I can just sync it back:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-rolling-your-own-cloud-storage-with-unison/2014-02-unison-example.png&#34;
	width=&#34;452&#34;
	height=&#34;134&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-rolling-your-own-cloud-storage-with-unison/2014-02-unison-example_hu_31b27a694fa5e366.png 480w, https://mike42.me/blog/2014-02-rolling-your-own-cloud-storage-with-unison/2014-02-unison-example_hu_570cc7706f03769.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;337&#34;
		data-flex-basis=&#34;809px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;With most ISP&amp;rsquo;s offering static addresses, you could even put a NAS on the internet to sync with, which would basically be a home DropBox.&lt;/p&gt;
&lt;h2 id=&#34;laptop-and-desktop-example&#34;&gt;Laptop and desktop example
&lt;/h2&gt;&lt;p&gt;Unison is in most Linux distributions. On Debian or Ubuntu, you can install it with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install unison
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;mike&lt;strong&gt;book&lt;/strong&gt; has a profile called &lt;code&gt;mikebox.prf&lt;/code&gt;, located in &lt;code&gt;/home/mike/.unison/&lt;/code&gt;, which tells it to keep a copy of its home directory on mike&lt;strong&gt;box&lt;/strong&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;root&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;home&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mike&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;root&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ssh&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mike&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mikebox&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;home&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mike&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Remote&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mikebook&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;ignore&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;ignore&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;iso&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;ignore&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;img&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;ignore&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Name&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;unison&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;log&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;ignore&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;BelowPath&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Downloads&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;ignore&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;BelowPath&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;workspace&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Everything can be brought up to speed with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;unison -batch mikebox
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If &lt;code&gt;mikebook&lt;/code&gt; is running out of space, then I can drag files out of Remote/mikebook to somewhere else, and they simply vanish from the laptop next time it is synchronised.&lt;/p&gt;
&lt;h2 id=&#34;notes&#34;&gt;Notes
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Remote paths require that extra &lt;code&gt;/&lt;/code&gt; in the filename.&lt;/li&gt;
&lt;li&gt;Hidden folders seem to be skipped, so keep a copy of your &lt;code&gt;.prf&lt;/code&gt; file in case you blow up your computer.&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>A tour of ReactOS 0.3.15</title>
        <link>https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15</link>
        <pubDate>Sat, 01 Feb 2014 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15</guid>
        <description>&lt;p&gt;ReactOS is a project which aims to create an open source operating system which is binary-compatible with Windows. Although it is still cautiously labelled &amp;ldquo;alpha&amp;rdquo;, its basic use is about as reliable as Windows once was.&lt;/p&gt;
&lt;p&gt;This post runs through the steps to install ReactOS 0.3.15 as a KVM guest on Linux, and shows  what you can expect from a freshly-installed system,&lt;/p&gt;
&lt;h2 id=&#34;preparation&#34;&gt;Preparation
&lt;/h2&gt;&lt;p&gt;Before attempting anything, check that you a CPU supports &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/X86_virtualization#AMD_virtualization_.28AMD-V.29&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Intel VT or AMD-V&lt;/a&gt;. This command will return the number of CPU cores with &lt;code&gt;svm&lt;/code&gt; or &lt;code&gt;vmx&lt;/code&gt; flags:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat /proc/cpuinfo | grep -E &amp;#39;svm|vmx&amp;#39; | wc -l
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now download the ReactOS 0.3.15 disk from &lt;a class=&#34;link&#34; href=&#34;http://www.reactos.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;reactos.org&lt;/a&gt;, extract it to get the &lt;code&gt;.iso&lt;/code&gt;, and fetch some packages if you don&amp;rsquo;t have them installed:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install libvirt-bin kvm qemu-utils
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Prepare a disk image to install to. If your hardware is slower, then a raw image is a better idea than the &lt;code&gt;qcow2&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qemu-img --help
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qemu-img create -f qcow2 reactos.img 4G
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The working directory now has:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mike@mikebox:~/vm/reactos$ ls -Ahl
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;total 77M
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-rw-r--r-- 1 mike mike  77M May 19  2013 ReactOS-BootCD.iso
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-rw-r--r-- 1 mike mike 193K Jan 30 21:05 reactos.img
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;installation-and-first-boot&#34;&gt;Installation and first boot
&lt;/h2&gt;&lt;p&gt;The &lt;code&gt;kvm&lt;/code&gt; command will pop up a window with the guest operating system. To boot from the install disk, run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kvm -hda reactos.img --cdrom ReactOS-BootCD.iso -vga std -localtime -net nic,model=ne2k_pci -net user
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The meaning of each of these options is:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;code&gt;-hda reactos.img&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;Sets the HDD image file.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;--cdrom ReactOS-BootCD.iso&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;Sets the CD-ROM image file. Because &lt;code&gt;reactos.img&lt;/code&gt; is blank, this will boot.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;-vga std&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;Sets the VGA card.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;-localtime&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;Emulates a system clock in local time, rather than UTC.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;-net nic,model=ne2k_pci&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;Sets the network card to something ReactOS will recognise.&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;-net user&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;Enables user-mode networking. Your computer will emulate a network and pass on TCP and UDP connections. This is the easiest mode to use, but ICMP packets (such as pings) will not work, and the VM will not be accessible from other computers.&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;Installation was fast, error-free, and did not require a network connection. The first screen capture below was taken at 16:04:49, and the desktop was captured at 16:06:07 (1 minute 18 seconds later). Most of that time would have been wasted waiting for user input.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-001.png&#34;
	width=&#34;720&#34;
	height=&#34;400&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-001_hu_a860d4eb5a2e9b46.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-001_hu_f70d8cd82fbbb08b.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;180&#34;
		data-flex-basis=&#34;432px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-002.png&#34;
	width=&#34;720&#34;
	height=&#34;400&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-002_hu_60a711468632085.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-002_hu_add2670d16240e1e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;180&#34;
		data-flex-basis=&#34;432px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-003.png&#34;
	width=&#34;720&#34;
	height=&#34;400&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-003_hu_7d36ed07b177bc37.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-003_hu_4ff147316e7fa499.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;180&#34;
		data-flex-basis=&#34;432px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-004.png&#34;
	width=&#34;720&#34;
	height=&#34;400&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-004_hu_498c2035e53796f1.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-004_hu_1ef9acace442cc17.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;180&#34;
		data-flex-basis=&#34;432px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-005.png&#34;
	width=&#34;720&#34;
	height=&#34;400&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-005_hu_ff52693e42473c90.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-005_hu_17dae46033494b35.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;180&#34;
		data-flex-basis=&#34;432px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-006.png&#34;
	width=&#34;720&#34;
	height=&#34;400&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-006_hu_8cc06835ae56fda3.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-006_hu_73d0499b702e0dd0.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;180&#34;
		data-flex-basis=&#34;432px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-007.png&#34;
	width=&#34;720&#34;
	height=&#34;400&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-007_hu_c8c6b19e5fa4f287.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-007_hu_807cbf5325087811.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;180&#34;
		data-flex-basis=&#34;432px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-008.png&#34;
	width=&#34;720&#34;
	height=&#34;400&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-008_hu_9ba6810b0cec01e9.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-008_hu_3d5d93fabf9e1cca.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;180&#34;
		data-flex-basis=&#34;432px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-009.png&#34;
	width=&#34;720&#34;
	height=&#34;400&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-009_hu_8619bd35026a6673.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-009_hu_8c71e177a3da67ca.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;180&#34;
		data-flex-basis=&#34;432px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-010.png&#34;
	width=&#34;720&#34;
	height=&#34;400&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-010_hu_9d3c8069c927384d.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-010_hu_dc4d852ec996a27f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;180&#34;
		data-flex-basis=&#34;432px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;After copying files, the installer reboots to a more user-friendly mode (similar to the Windows installer):&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-011.png&#34;
	width=&#34;720&#34;
	height=&#34;400&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-011_hu_c532cd998a2f45b7.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-011_hu_9c77acf35f4258dc.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;180&#34;
		data-flex-basis=&#34;432px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-012.png&#34;
	width=&#34;720&#34;
	height=&#34;400&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-012_hu_c7831df7e1785343.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-012_hu_dd53ae73073d3925.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;180&#34;
		data-flex-basis=&#34;432px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-013.png&#34;
	width=&#34;640&#34;
	height=&#34;480&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-013_hu_ea7d4fe173ac16c7.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-013_hu_a949a4ff95d3cd3d.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-014.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-014_hu_21e1b8a738d81976.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-014_hu_f10e29365716bd64.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-015.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-015_hu_8646d2464530f03a.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-015_hu_a92f63806ef3d753.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-016.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-016_hu_9b0cfc728c0ad74e.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-016_hu_97b20f89ab5e6ade.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-017.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-017_hu_55430a00fa1da979.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-017_hu_9214480c1d040756.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-018.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-018_hu_8e88421018c5cbc8.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-018_hu_1b1e927c7cdeeb78.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-019.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-019_hu_9d08d13e800c4d77.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-019_hu_c542e25ca8ccb508.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-020.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-020_hu_53cbf23438c43b97.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-020_hu_81b6803624b219ee.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-021.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-021_hu_ebf07ccef40b1ca8.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-021_hu_ee7d545f09a478f7.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-022.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-022_hu_fcd7712c541f6aa6.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-022_hu_cf7baf30cccd63cb.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-023.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-023_hu_b532a4e59864b6c4.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-install-023_hu_5b22a8978102ad2b.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;the-installed-system&#34;&gt;The installed system
&lt;/h2&gt;&lt;p&gt;After installation, the &lt;code&gt;--cdrom&lt;/code&gt; option can be dropped:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kvm -hda reactos.img -vga std -localtime -net nic,model=ne2k_pci -net user
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first thing I did was correct the colour depth, and then attempt to install VLC. This did not turn out well (the console screen is &lt;a class=&#34;link&#34; href=&#34;http://en.wikibooks.org/wiki/QEMU/Monitor&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;QEMU-monitor&lt;/a&gt;):&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-001.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-001_hu_2578a63aced9e50a.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-001_hu_626265803d99cdbb.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-002.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-002_hu_54eb801a4ea6796d.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-002_hu_b81a6244a12c6d81.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-003.png&#34;
	width=&#34;640&#34;
	height=&#34;384&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-003_hu_978bb2910ca018f0.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-003_hu_8ffcce389f1e746.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;166&#34;
		data-flex-basis=&#34;400px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-004.png&#34;
	width=&#34;640&#34;
	height=&#34;480&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-004_hu_7620d0b6fce28ce2.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-004_hu_5bd5895d8889bebf.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I used command prompt to verify that networking was fine (note the lack of ICMP in user-mode networking):&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-010.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-010_hu_e0c9cb7da44fa91b.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-010_hu_1764ca61882b884e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-011.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-011_hu_eac60fabde3532e6.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-011_hu_a1fe03b2b45b5fac.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The Firefox 22 install worked, but it went awry after that. Several reboots later I gave up:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-005.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-005_hu_d6de66bc6b92ffbe.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-005_hu_5937621e5d15bdad.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-006.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-006_hu_79ac6dfcbfe30208.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-006_hu_3da6eb2150d55c6f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-007.png&#34;
	width=&#34;640&#34;
	height=&#34;480&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-007_hu_21ea7fc4f3ed49dd.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-007_hu_233eb7c2b2acb59c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The built-in programs were much more usable:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-008.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-008_hu_c80d4500607fd0ec.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-008_hu_8a6856d31e315cdc.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-009.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-009_hu_eebcb09b5dd1e7f2.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-009_hu_db771ecb6a9c8a4a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-012.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-012_hu_8d924409cc5cc541.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-012_hu_ee3c92a8622e2308.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-013.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-013_hu_4a149dee48a98db5.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-013_hu_817662ea27448f01.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-014.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-014_hu_21b40630c5cb58ec.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-014_hu_d209443d10d2ac9a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;PuTTY installed flawlessly, and I was able to SSH to the host computer:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-015.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-015_hu_fc08621916871914.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-015_hu_61bd61405db14f39.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-016.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-016_hu_5cc14f1abc0f23d9.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-016_hu_65d28712701723d9.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-017.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-017_hu_14f083365a2491dc.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-017_hu_b3fb97e73f4700be.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-018.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-018_hu_db33ba9b66929a20.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-018_hu_b4d530c3e41f4530.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-019.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-019_hu_ecadfe6f4aa82deb.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-019_hu_f7d131cb6e3e61d9.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-020.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-020_hu_9eb2d49ef234afbd.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-020_hu_21d9d4105677447e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;An example of a frozen program causing graphics glitches (Windows up to XP does this as well):&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-022.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-022_hu_f47d54771d343515.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-022_hu_52bfc906ac3deb5b.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;And an obligatory screenshot of the &amp;ldquo;Properties for System&amp;rdquo; dialog, showing the build as &lt;strong&gt;20130518-r59037&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-021.png&#34;
	width=&#34;800&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-021_hu_646db4bdaf459f62.png 480w, https://mike42.me/blog/2014-02-a-tour-of-reactos-0-3-15/2014-02-01-reactos-testing-021_hu_1fad82802486eef8.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;ReactOS is a cool idea and project, but the OS is still very glitchy. The built-in apps are stable and familiar-looking, but you would require a lot of patience (and a lot of rebooting) to use a ReactOS system for more than a few minutes.&lt;/p&gt;
&lt;p&gt;Being open source is a big plus, as there is no need to activate the installation or enter software keys. GNU/Linux users will already be accustomed to this.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Recovering auto-saved files in MySQL Workbench</title>
        <link>https://mike42.me/blog/2014-02-recovering-auto-saved-files-in-mysql-workbench</link>
        <pubDate>Sat, 01 Feb 2014 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2014-02-recovering-auto-saved-files-in-mysql-workbench</guid>
        <description>&lt;p&gt;MySQL workbench is an open source tool for designing databases. As version 6.0.8, it is one of those programs where you need to save often, because the window you are working in will vanish every couple of hours.&lt;/p&gt;
&lt;h2 id=&#34;bug-1-cant-recover-files-that-werent-saved&#34;&gt;Bug #1: Can&amp;rsquo;t recover files that weren&amp;rsquo;t saved
&lt;/h2&gt;&lt;p&gt;I was unlucky enough to have forgotten to save my work when it crashed today, and found this nasty flaw in the &lt;a class=&#34;link&#34; href=&#34;http://dev.mysql.com/doc/workbench/en/wb-preferences-general.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;auto-recover feature&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Auto-save model interval: An open model that has not been saved will automatically be saved after this period. On loading a model file, MySQL Workbench will notify the user if the file was not previously saved correctly, due to a crash or power failure. MySQL Workbench can then attempt to recover the last auto-saved version. &lt;strong&gt;For automatic recovery to be available for a new file, it will have to have been saved at least once by the user.&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Uh oh! The file hadn&amp;rsquo;t been saved yet, so it&amp;rsquo;s gone right? According to &lt;code&gt;wb_model_file.cpp&lt;/code&gt;, this is not the case. The auto-save file is always written, but the recovery process wont be started until you try to use it again (which will never happen if you don&amp;rsquo;t have an old saved version):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/* Auto-saving
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; * Auto-saving works by saving the model document file (the XML) to the expanded document folder
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; * from time to time, named as document-autosave.mwb.xml. The expanded document folder is
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; * automatically deleted when it is closed normally.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; * When a document is opened, it will check if there already is a document folder for that file
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; * and if so, the recovery function will kick in, using the autosave XML file.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; */
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So under &lt;code&gt;~/.mysql/workbench/&lt;/code&gt;, I found a &lt;code&gt;newmodel.mwbd&lt;/code&gt; folder. Workbench files are &lt;code&gt;.zip&lt;/code&gt; files in disguise, so I compared it to a test file. It had all the same content, but with a &lt;code&gt;document-autosave.xml&lt;/code&gt;, rather than a &lt;code&gt;document.xml&lt;/code&gt; (see test file below):&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-recovering-auto-saved-files-in-mysql-workbench/2014-01-mwb-archive.png&#34;
	width=&#34;708&#34;
	height=&#34;302&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-recovering-auto-saved-files-in-mysql-workbench/2014-01-mwb-archive_hu_ef1502f97d26619c.png 480w, https://mike42.me/blog/2014-02-recovering-auto-saved-files-in-mysql-workbench/2014-01-mwb-archive_hu_bf7bcf9615197153.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;234&#34;
		data-flex-basis=&#34;562px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Cool, so I&amp;rsquo;d just rename the file, compress the whole lot and make it a &lt;code&gt;.mwb&lt;/code&gt;? No such luck.&lt;/p&gt;
&lt;h2 id=&#34;bug-2-file-roller-cant-compress--files&#34;&gt;Bug #2: File Roller can&amp;rsquo;t compress &amp;lsquo;@&amp;rsquo; files
&lt;/h2&gt;&lt;p&gt;Possibly because of the &lt;code&gt;-@&lt;/code&gt; command-line option in the &lt;code&gt;zip&lt;/code&gt; command, File Roller refused to work with these files.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-recovering-auto-saved-files-in-mysql-workbench/2014-01-fileroller-at.png&#34;
	width=&#34;645&#34;
	height=&#34;237&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-recovering-auto-saved-files-in-mysql-workbench/2014-01-fileroller-at_hu_1c37658b18013559.png 480w, https://mike42.me/blog/2014-02-recovering-auto-saved-files-in-mysql-workbench/2014-01-fileroller-at_hu_2448e0ffa2f104f1.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;272&#34;
		data-flex-basis=&#34;653px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Luckily, the &lt;code&gt;document.mwb.xml&lt;/code&gt; file alone is enough for the file to be recognised and recovered from the auto-saved files:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-02-recovering-auto-saved-files-in-mysql-workbench/2014-01-mysqlwb-recovered.png&#34;
	width=&#34;1018&#34;
	height=&#34;570&#34;
	srcset=&#34;https://mike42.me/blog/2014-02-recovering-auto-saved-files-in-mysql-workbench/2014-01-mysqlwb-recovered_hu_d433e0b6f724691c.png 480w, https://mike42.me/blog/2014-02-recovering-auto-saved-files-in-mysql-workbench/2014-01-mysqlwb-recovered_hu_176429ce305689dd.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;178&#34;
		data-flex-basis=&#34;428px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The take-away from this?&lt;/strong&gt; Save your work. In 2014, you still can&amp;rsquo;t count on auto-save to do this!&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Scripted screen captures</title>
        <link>https://mike42.me/blog/2014-01-scripted-screen-captures</link>
        <pubDate>Fri, 31 Jan 2014 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2014-01-scripted-screen-captures</guid>
        <description>&lt;p&gt;This is a script which I put together for capturing a window&amp;rsquo;s content as it changes, because &amp;ldquo;Print Screen and crop&amp;rdquo; gets old very quickly!&lt;/p&gt;
&lt;p&gt;It saves me a lot of time when working in virtual machines or creating user docs, as it means that every step (and error message) is captured.&lt;/p&gt;
&lt;p&gt;The commands used here are in the &lt;code&gt;x11-utils&lt;/code&gt; and &lt;code&gt;netpbm&lt;/code&gt; and &lt;code&gt;x11-apps&lt;/code&gt; packages on Debian.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install x11-utils netpbm x11-apps
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;capturesh&#34;&gt;capture.sh
&lt;/h2&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Click a window to start capturing it.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;window&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;xwininfo -int &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep &lt;span class=&#34;s1&#34;&gt;&amp;#39;Window id:&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; cut -d&lt;span class=&#34;s1&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt; -f4&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; -n &lt;span class=&#34;s2&#34;&gt;&amp;#34;Capturing window &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$window&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;prev&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;empty&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; -n &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; md5sum &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; cut -d&lt;span class=&#34;s1&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt; -f1&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;captured&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;captured.txt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; -n &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &amp;gt; &lt;span class=&#34;nv&#34;&gt;$captured&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$prev&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; !&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$empty&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;md5sum&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;xwd -id &lt;span class=&#34;nv&#34;&gt;$window&lt;/span&gt; 2&amp;gt; /dev/null &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; xwdtopnm 2&amp;gt; /dev/null &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; md5sum &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; cut -d&lt;span class=&#34;s1&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt; -f1&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; grep -Fxq &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$md5sum&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$captured&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; -n &lt;span class=&#34;s2&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$md5sum&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; !&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$empty&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$md5sum&lt;/span&gt; &amp;gt;&amp;gt; &lt;span class=&#34;nv&#34;&gt;$captured&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; -n &lt;span class=&#34;nv&#34;&gt;$md5sum&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nv&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;date --iso&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;-capture-&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;printf&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;%03d&amp;#34;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;.png
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            xwd -id &lt;span class=&#34;nv&#34;&gt;$window&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; xwdtopnm 2&amp;gt; /dev/null &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; pnmtopng 2&amp;gt; /dev/null &amp;gt; &lt;span class=&#34;nv&#34;&gt;$file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nv&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;$&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;i+1&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    sleep &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;prev&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$md5sum&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Empty screen capture received. Quitting. (did you close the window?)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;example&#34;&gt;Example
&lt;/h2&gt;&lt;p&gt;If you wanted to document a &amp;ldquo;Malformed Expression&amp;rdquo; error in Gnome Calculator, you can run capture.sh and then demonstrate it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ./capture.sh
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Click a window to start capturing it.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Capturing window 31457283
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;3bbe32ef05f49ae65922fcfedc842828
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;c0cef7d3108263fbb1beaa7b52492e6a
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;fd6df04c4ad844bb4a2f27be29dffb29
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;6ba0fb7ee1ca85640998013c6a258520.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;bb061cc56fa3822f9764c0f6af2156df
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;5f788568c7f34cda55a1680ac72e1cf0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dca714e6691a3a239914106996905047
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0bf916ba3f96f3def57191174e55dea0.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2a4a2589662901d9a55d1e170ffbd322....
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Empty screen capture received. Quitting. (did you close the window?)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The lines are checksums of PNM data, and the dots are times when no screenshot was saved. This guarantees that each file in the output is unique:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-01-scripted-screen-captures/2014-01-capture-demo.png&#34;
	width=&#34;613&#34;
	height=&#34;332&#34;
	srcset=&#34;https://mike42.me/blog/2014-01-scripted-screen-captures/2014-01-capture-demo_hu_878712b4391ce1f0.png 480w, https://mike42.me/blog/2014-01-scripted-screen-captures/2014-01-capture-demo_hu_f2773c99bad8873.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Example of captured files&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;184&#34;
		data-flex-basis=&#34;443px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;captured.txt&lt;/code&gt; file simply contains the list of checksums, and is useless after the script terminates.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Brother HL-2270DW on Linux</title>
        <link>https://mike42.me/blog/2014-01-brother-hl-2270dw-on-linux</link>
        <pubDate>Thu, 23 Jan 2014 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2014-01-brother-hl-2270dw-on-linux</guid>
        <description>&lt;p&gt;The Brother HL-2270DW is one of the best budget laser printers around, with third party consumables readily available on eBay.&lt;/p&gt;
&lt;p&gt;The printer has a network port on the back of it, which is great news for GNU/Linux users, because networked printers tend to speak standard protocols.&lt;/p&gt;
&lt;p&gt;The fastest way to get this printer working without Windows is to plug it in and log in via the web. The default settings have DHCP enabled. Here are a few pieces of cryptic knowledge that helped me:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;To reset the print server settings, hold &amp;ldquo;GO&amp;rdquo; on startup, then let go and press it 6 times.&lt;/li&gt;
&lt;li&gt;The default admin login is &lt;strong&gt;admin / access&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;On my printer (Firmware 1.10), printing network settings by holding &amp;ldquo;GO&amp;rdquo; for 10 seconds caused the network card (Brother NC-7800w) activity lights to go off, requiring a reboot.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;On Debian, there is no &amp;ldquo;Brother HL-220DW&amp;rdquo; CUPS driver on the list, but I found the following driver to work fine (and allow duplex):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Brother HL-2170W Foomatic/hpijs-pcl5e (recommended)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To use this driver, you will need to install the HP Linux Printing and Imaging printer driver:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install printer-driver-hpijs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>Crash course in handling web traffic spikes</title>
        <link>https://mike42.me/blog/2014-01-crash-course-in-handling-web-traffic-spikes</link>
        <pubDate>Tue, 14 Jan 2014 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2014-01-crash-course-in-handling-web-traffic-spikes</guid>
        <description>&lt;p&gt;Yesterday, there was a small earthquake in Melbourne. Within a few minutes, the &lt;a href=&#34;http://www.ga.gov.au/&#34;&gt;Geoscience Australia&lt;/a&gt; web-page was delivering 503 Errors, quite possibly due to the load.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-01-crash-course-in-handling-web-traffic-spikes/2014-01-geoscience-au-offline.png&#34;
	width=&#34;811&#34;
	height=&#34;614&#34;
	srcset=&#34;https://mike42.me/blog/2014-01-crash-course-in-handling-web-traffic-spikes/2014-01-geoscience-au-offline_hu_26ac7acdfc7a73e8.png 480w, https://mike42.me/blog/2014-01-crash-course-in-handling-web-traffic-spikes/2014-01-geoscience-au-offline_hu_6d3278e730468896.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;132&#34;
		data-flex-basis=&#34;317px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This blog post is just a few quick thoughts about building websites to handle load.&lt;/p&gt;
&lt;h2 id=&#34;why-websites-crash&#34;&gt;Why websites crash
&lt;/h2&gt;&lt;p&gt;Websites stop working under heavy load because the server doesn&amp;rsquo;t have enough resources to process everything. This is usually one of:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Bandwidth saturation&lt;/strong&gt;, indicated by timeouts and super slow load times.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Webserver or cache overload&lt;/strong&gt;, indicated by refused connections or server (5XX) errors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database server overload&lt;/strong&gt;, indicated by server errors.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A simple database-driven website might process a request like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-01-crash-course-in-handling-web-traffic-spikes/2014-01-webserver-only.png&#34;
	width=&#34;675&#34;
	height=&#34;61&#34;
	srcset=&#34;https://mike42.me/blog/2014-01-crash-course-in-handling-web-traffic-spikes/2014-01-webserver-only_hu_be7f6b359ee3558f.png 480w, https://mike42.me/blog/2014-01-crash-course-in-handling-web-traffic-spikes/2014-01-webserver-only_hu_70ab2d4d0e6c77b0.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;1106&#34;
		data-flex-basis=&#34;2655px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;set-up-a-squid-cache&#34;&gt;Set up a squid cache
&lt;/h2&gt;&lt;p&gt;For sites which uses a database to serve requests, a good cache setup is essential. This is another server (or server process), which serves pages that aren&amp;rsquo;t changing. A page only needs to be generated as often as it changes:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-01-crash-course-in-handling-web-traffic-spikes/2014-01-webserver-cached.png&#34;
	width=&#34;792&#34;
	height=&#34;68&#34;
	srcset=&#34;https://mike42.me/blog/2014-01-crash-course-in-handling-web-traffic-spikes/2014-01-webserver-cached_hu_7cf30da3ccb85e5.png 480w, https://mike42.me/blog/2014-01-crash-course-in-handling-web-traffic-spikes/2014-01-webserver-cached_hu_89b560e0cccec0c1.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;1164&#34;
		data-flex-basis=&#34;2795px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;squid&lt;/strong&gt; is a good open source starting point if you are administering a server which struggles under load.&lt;/p&gt;
&lt;h2 id=&#34;round-robin-dns&#34;&gt;Round-robin DNS
&lt;/h2&gt;&lt;p&gt;Without running a hardware load-balancer (read: spending real money), you can have clients connect to different servers by using round-robin DNS.&lt;/p&gt;
&lt;p&gt;Each time a DNS lookup is issued, a different address can be returned, allowing you to have several caches at work.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2014-01-crash-course-in-handling-web-traffic-spikes/2014-01-webserver-cache-rotor.png&#34;
	width=&#34;457&#34;
	height=&#34;601&#34;
	srcset=&#34;https://mike42.me/blog/2014-01-crash-course-in-handling-web-traffic-spikes/2014-01-webserver-cache-rotor_hu_b86fc1e464e136fc.png 480w, https://mike42.me/blog/2014-01-crash-course-in-handling-web-traffic-spikes/2014-01-webserver-cache-rotor_hu_e6446479d476500e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;76&#34;
		data-flex-basis=&#34;182px&#34;
	
&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Missile Launcher on Raspberry Pi</title>
        <link>https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi</link>
        <pubDate>Sat, 21 Dec 2013 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi</guid>
        <description>&lt;p&gt;This post covers a few setups to experiment with if you have a DreamCheeky USB missile launcher and a Raspberry Pi.&lt;/p&gt;
&lt;p&gt;A &lt;a class=&#34;link&#34; href=&#34;http://www.thinkgeek.com/product/8a0f/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;newer version&lt;/a&gt; is being sold on ThinkGeek, but the one I used looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-missile.jpg&#34;
	width=&#34;450&#34;
	height=&#34;338&#34;
	srcset=&#34;https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-missile_hu_62181251b3d4c35f.jpg 480w, https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-missile_hu_bf19d478bc4f58da.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;DreamCheeky USB Missile Launcher&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;319px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;setup-1-direct-to-pc&#34;&gt;Setup 1: Direct to PC
&lt;/h2&gt;&lt;p&gt;The launcher comes with some software to let you connect it straight to a computer. Of course, USB can only go 5 metres, which is not much fun for cubicle warfare:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-missile-setup-1.png&#34;
	width=&#34;464&#34;
	height=&#34;145&#34;
	srcset=&#34;https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-missile-setup-1_hu_d12ce8bd725738eb.png 480w, https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-missile-setup-1_hu_b51c17b7e5a3c4af.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;USB Missile Launcher setup with USB cable to PC&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;320&#34;
		data-flex-basis=&#34;768px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I included this setup because it is the easiest way for Debian/Ubuntu users to test that they can use &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/missile&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this driver&lt;/a&gt;, which is needed for the other setups.&lt;/p&gt;
&lt;h2 id=&#34;setup-2-networked-with-raspberry-pi&#34;&gt;Setup 2: Networked with Raspberry Pi
&lt;/h2&gt;&lt;p&gt;So for this setup, you need a Raspberry Pi Model B. They look like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-raspberry-pi.jpg&#34;
	width=&#34;450&#34;
	height=&#34;318&#34;
	srcset=&#34;https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-raspberry-pi_hu_8621f9ea18bdf840.jpg 480w, https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-raspberry-pi_hu_b91bd8c629900e9e.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Raspberry Pi Model B&#34;
	
	
	
		class=&#34;gallery-image img-sm&#34; 
		data-flex-grow=&#34;141&#34;
		data-flex-basis=&#34;339px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Running Raspbian, upgrade to Debian Jessie, and compile the code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;apt-get install git libusb-1.0-0-dev libncurses-dev gcc g++
git clone --recursive https://github.com/mike42/missile
cd missile
make&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can then place the pi anywhere with network and power:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-missile-setup-2.png&#34;
	width=&#34;646&#34;
	height=&#34;291&#34;
	srcset=&#34;https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-missile-setup-2_hu_889c6ab4e08d817a.png 480w, https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-missile-setup-2_hu_583788e062230780.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;USB Missile launcher setup with Raspberry Pi&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;221&#34;
		data-flex-basis=&#34;532px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;To operate the launcher remotely, use SSH to log in, and run &lt;tt&gt;missile/bin/keyboard-ctl&lt;/tt&gt;.
&lt;h2 id=&#34;setup-3-wireless-with-raspberry-pi-and-battery&#34;&gt;Setup 3: Wireless with Raspberry Pi and Battery
&lt;/h2&gt;&lt;p&gt;Of course, network and power can be provided with a power bank and Wi-Fi adapter:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-powerbank.jpg&#34;
	width=&#34;450&#34;
	height=&#34;338&#34;
	srcset=&#34;https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-powerbank_hu_82ace43f82fd1fd8.jpg 480w, https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-powerbank_hu_84e601ab541a765e.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Power Bank for mobile phone&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;319px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-wifi.jpg&#34;
	width=&#34;450&#34;
	height=&#34;255&#34;
	srcset=&#34;https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-wifi_hu_7af2c82beaa4912d.jpg 480w, https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-wifi_hu_9894692bbf8a5bb6.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;USB WiFi Adapter&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;176&#34;
		data-flex-basis=&#34;423px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The Wi-Fi adapter will take some work to set up (see &lt;a class=&#34;link&#34; href=&#34;https://wiki.debian.org/WiFi/HowToUse&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Debian Wiki&lt;/a&gt;), so I won&amp;rsquo;t document that here. You will need a power bank that has enough power for the Raspberry Pi with launcher and wifi. Mine had to be close to fully charged to work.&lt;/p&gt;
&lt;p&gt;A diagram of this setup:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-missile-setup-3.png&#34;
	width=&#34;617&#34;
	height=&#34;284&#34;
	srcset=&#34;https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-missile-setup-3_hu_9124282a9852e634.png 480w, https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-missile-setup-3_hu_73219e9638cea34a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;USB Missile launcher setup with Raspberry Pi (WiFi and Battery)&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;217&#34;
		data-flex-basis=&#34;521px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap-up
&lt;/h2&gt;&lt;p&gt;The reason this helps with cubicle warfare is simple: The launcher, Raspberry Pi and battery can be fitted into a tissue box or other small space. Proof:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-box-interior.jpg&#34;
	width=&#34;450&#34;
	height=&#34;338&#34;
	srcset=&#34;https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-box-interior_hu_3ef46c3aac9c3872.jpg 480w, https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-box-interior_hu_6f8129f371047b37.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Box interior&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;319px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;On a desk you would see this as:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-box-exterior.jpg&#34;
	width=&#34;450&#34;
	height=&#34;338&#34;
	srcset=&#34;https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-box-exterior_hu_b38330352fb90efb.jpg 480w, https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-box-exterior_hu_74c65a9acf6d76.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Box exterior&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;319px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-box-open.jpg&#34;
	width=&#34;450&#34;
	height=&#34;338&#34;
	srcset=&#34;https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-box-open_hu_c0067cb9aff27b06.jpg 480w, https://mike42.me/blog/2013-12-missile-launcher-on-raspberry-pi/2013-12-box-open_hu_d61ad5b81fe825b6.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Box open&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;319px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;And a quick demo for completeness:&lt;/p&gt;

      &lt;div
          style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
        &lt;iframe
          src=&#34;https://player.vimeo.com/video/82488263?dnt=0&#34;
            style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allow=&#34;fullscreen&#34;&gt;
        &lt;/iframe&gt;
      &lt;/div&gt;

&lt;p&gt;For this demo, the Pi is connected to DC power, because the battery didn&amp;rsquo;t quite have enough juice to power everything.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Enabling graphical boot on Debian GNU/Linux</title>
        <link>https://mike42.me/blog/2013-12-enabling-graphical-boot-on-debian-gnu-linux</link>
        <pubDate>Fri, 20 Dec 2013 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2013-12-enabling-graphical-boot-on-debian-gnu-linux</guid>
        <description>&lt;p&gt;Unlike most desktop Linux distributions around today, Debian&amp;rsquo;s default boot screen is still text:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-12-enabling-graphical-boot-on-debian-gnu-linux/2013-12-debian-boot.png&#34;
	width=&#34;720&#34;
	height=&#34;400&#34;
	srcset=&#34;https://mike42.me/blog/2013-12-enabling-graphical-boot-on-debian-gnu-linux/2013-12-debian-boot_hu_ef729d93a7f7c8e4.png 480w, https://mike42.me/blog/2013-12-enabling-graphical-boot-on-debian-gnu-linux/2013-12-debian-boot_hu_10e83e1438ebe0c7.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Debian’s text-mode booting&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;180&#34;
		data-flex-basis=&#34;432px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I imagine that this is because there is no distinction between &amp;ldquo;Desktop&amp;rdquo; and &amp;ldquo;Server&amp;rdquo; editions in the Debian world (see &lt;a class=&#34;link&#34; href=&#34;https://wiki.debian.org/tasksel&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;tasksel&lt;/a&gt;), so a text-mode boot will work on every type of installation.&lt;/p&gt;
&lt;p&gt;Luckily, if you want a graphical boot screen, you can simply &lt;code&gt;apt-get install&lt;/code&gt; a package called &lt;code&gt;plymouth&lt;/code&gt; and configure it &lt;a class=&#34;link&#34; href=&#34;https://wiki.debian.org/plymouth&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;according to these instructions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The result looks more suited to a desktop PC (screen capture from &lt;a class=&#34;link&#34; href=&#34;https://wiki.debian.org/DebianArt/Themes/Joy#Plymouth_:&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;here&lt;/a&gt;):&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-12-enabling-graphical-boot-on-debian-gnu-linux/2013-12-debian-plymouth.png&#34;
	width=&#34;400&#34;
	height=&#34;225&#34;
	srcset=&#34;https://mike42.me/blog/2013-12-enabling-graphical-boot-on-debian-gnu-linux/2013-12-debian-plymouth_hu_e5d22c6a75cf88ec.png 480w, https://mike42.me/blog/2013-12-enabling-graphical-boot-on-debian-gnu-linux/2013-12-debian-plymouth_hu_b17bbf68b28c0728.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Debian’s plymouth boot screen&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;plymouth-install-notes&#34;&gt;Plymouth install notes
&lt;/h2&gt;&lt;p&gt;There is a comment in &lt;code&gt;/etc/default/grub&lt;/code&gt; which suggests checking supported graphics modes, which is a Good Idea(TM):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# The resolution used on graphical terminal
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# note that you can use only modes which your graphic card supports via VBE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# you can see them in real GRUB with the command `vbeinfo&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#GRUB_GFXMODE=640x480
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The theme for &amp;ldquo;wheezy&amp;rdquo; was called &lt;a class=&#34;link&#34; href=&#34;https://wiki.debian.org/DebianDesktop/Artwork/Wheezy&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Joy&lt;/a&gt;, so if you have &lt;a class=&#34;link&#34; href=&#34;http://packages.debian.org/wheezy/all/desktop-base/filelist&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;desktop-base&lt;/a&gt; installed, you should:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/usr/sbin/plymouth-set-default-theme joy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I tried to get this working in a virtual machine to get an actual screen capture, but on KVM this appears to be quite tricky, due to  emulated graphics.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>USB Missile Launcher</title>
        <link>https://mike42.me/blog/2013-12-usb-missile-launcher</link>
        <pubDate>Thu, 19 Dec 2013 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2013-12-usb-missile-launcher</guid>
        <description>&lt;p&gt;Back in February I coded up a userspace driver to control a USB foam missile launcher manufactured by DreamCheeky. The video below shows one of the example programs in action.&lt;/p&gt;

      &lt;div
          style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
        &lt;iframe
          src=&#34;https://player.vimeo.com/video/82277767?dnt=0&#34;
            style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allow=&#34;fullscreen&#34;&gt;
        &lt;/iframe&gt;
      &lt;/div&gt;

&lt;p&gt;The code being executed in the video is from &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/missile/blob/master/examples/basic-sync/basic-sync.cpp&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;basic-sync.cpp&lt;/a&gt;, the simplest demonstration I could think of:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Missile *launcher = new Missile(launcherHandle);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;launcher -&amp;gt; async = false;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;launcher -&amp;gt; move(ML_DOWN, 1000);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;launcher -&amp;gt; move(ML_UP, 1000);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;launcher -&amp;gt; move(ML_LEFT, 1000);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;launcher -&amp;gt; move(ML_RIGHT, 1000);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;launcher -&amp;gt; fire();
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;delete launcher;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The USB driver uses &lt;a class=&#34;link&#34; href=&#34;http://www.libusb.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;libusb&lt;/a&gt;, and was coded in response to &lt;a class=&#34;link&#34; href=&#34;https://bugs.launchpad.net/ubuntu/&amp;#43;source/pyrocket/&amp;#43;bug/994552&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this trivial bug&lt;/a&gt; not being fixed in the Ubuntu repositories for over a year.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to graph ASX data with gnuplot</title>
        <link>https://mike42.me/blog/2013-12-how-to-graph-asx-data-with-gnuplot</link>
        <pubDate>Fri, 13 Dec 2013 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2013-12-how-to-graph-asx-data-with-gnuplot</guid>
        <description>&lt;p&gt;This post is not about economics, it&amp;rsquo;s about scripting. People who follow stocks love to see historic prices. Here I&amp;rsquo;ll show you how to get historic ASX data and do a simple plot with the wonderful open-source tool &lt;a class=&#34;link&#34; href=&#34;http://www.gnuplot.info/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;gnuplot&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;getting-the-data&#34;&gt;Getting the data
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;m uncertain who runs it, but &lt;a class=&#34;link&#34; href=&#34;http://www.asxhistoricaldata.com/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this site&lt;/a&gt; offers &lt;code&gt;.zip&lt;/code&gt; files containing basic daily data, updated each weekend. The archives have CSV files in them:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-12-how-to-graph-asx-data-with-gnuplot/2013-12-asx-source-data.png&#34;
	width=&#34;756&#34;
	height=&#34;191&#34;
	srcset=&#34;https://mike42.me/blog/2013-12-how-to-graph-asx-data-with-gnuplot/2013-12-asx-source-data_hu_91a70394238ec232.png 480w, https://mike42.me/blog/2013-12-how-to-graph-asx-data-with-gnuplot/2013-12-asx-source-data_hu_984e86ad21c6e961.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;ASX source data&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;395&#34;
		data-flex-basis=&#34;949px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;To make these useful, I joined them together and imported them into &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/SQLite&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;sqlite&lt;/a&gt;. On Debian this is in the &lt;code&gt;sqlite3&lt;/code&gt; package.&lt;/p&gt;
&lt;p&gt;To turn the &lt;code&gt;.zip&lt;/code&gt; files into a &lt;code&gt;sqlite&lt;/code&gt; file:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Download the files for the time period you need, and put them in a folder called &amp;ldquo;&lt;code&gt;data&lt;/code&gt;&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Save the script below as &amp;ldquo;&lt;code&gt;import.sh&lt;/code&gt;&amp;rdquo; and run it.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Unzip all the data files and leave the text files in the &amp;#34;txt&amp;#34; folder.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rm -f asx-historic.db
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rm -Rf txt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir -p txt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; i in data/*&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; -n &lt;span class=&#34;s2&#34;&gt;&amp;#34;Extracting &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; .. &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	unzip -q &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; -d txt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mv txt/*/*.txt txt/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find . -empty -delete
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Combine the text files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; -n &lt;span class=&#34;s2&#34;&gt;&amp;#34;Combining files .. &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat txt/*.txt &amp;gt; txt/asx-historic.csv
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Import the text files into an sqlite db&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; -n &lt;span class=&#34;s2&#34;&gt;&amp;#34;Creating database .. &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sqlite3 asx-historic.db -batch &lt;span class=&#34;s&#34;&gt;&amp;lt;&amp;lt;EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;create table price (code CHAR(3), date DATE, open DECIMAL(10,3), close DECIMAL(10,3), low DECIMAL(10,3), high DECIMAL(10,3), vol);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;.separator ,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;.import txt/asx-historic.csv price
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After running &lt;code&gt;import.sh&lt;/code&gt;, the data is in a file called &amp;ldquo;&lt;code&gt;asx-historic.db&lt;/code&gt;&amp;rdquo;. You should re-run this script with extra data when it comes out.&lt;/p&gt;
&lt;h2 id=&#34;querying-an-sqlite-database&#34;&gt;Querying an sqlite database
&lt;/h2&gt;&lt;p&gt;That file is a database, so you can query it with &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/SQL&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;SQL&lt;/a&gt; like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mike@mikebox$ sqlite3 asx-historic.db
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SQLite version 3.8.1 2013-10-17 12:57:35
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Enter &amp;#34;.help&amp;#34; for instructions
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Enter SQL statements terminated with a &amp;#34;;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sqlite&amp;gt; select date, close from price where code=&amp;#39;ASX&amp;#39; order by date;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;20130603|37.68
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;20130604|37.1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;20130605|36.64
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;20130606|36.4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;graphing-closing-prices&#34;&gt;Graphing closing prices
&lt;/h2&gt;&lt;p&gt;Line graphs in gnuplot are very simple. Save this file as &lt;code&gt;line.gnuplot&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gnuplot&#34; data-lang=&#34;gnuplot&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;set&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;terminal&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pdf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;set&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;output&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fout&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;set&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;left&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;plot&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fin&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;using&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;w&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;lines&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;title&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;code&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &amp;ldquo;fout&amp;rdquo; (file out) &amp;ldquo;fin&amp;rdquo; (file in) and &amp;ldquo;code&amp;rdquo; are variables.&lt;/p&gt;
&lt;p&gt;This bash script lists closing prices for a code and saves them to a &lt;code&gt;.dat&lt;/code&gt; file under a folder called &amp;ldquo;plot&amp;rdquo;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;sqlite3 -separator &lt;span class=&#34;s1&#34;&gt;$&amp;#39;t&amp;#39;&lt;/span&gt; asx-historic.db &lt;span class=&#34;s2&#34;&gt;&amp;#34;select date, close from price where code=&amp;#39;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#39; order by date;&amp;#34;&lt;/span&gt; &amp;gt; plot/&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;.dat
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gnuplot -e &lt;span class=&#34;s2&#34;&gt;&amp;#34;code=&amp;#39;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#39;&amp;#34;&lt;/span&gt; -e &lt;span class=&#34;s2&#34;&gt;&amp;#34;fin=&amp;#39;plot/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;.dat&amp;#39;&amp;#34;&lt;/span&gt; -e &lt;span class=&#34;s2&#34;&gt;&amp;#34;fout=&amp;#39;plot/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;.pdf&amp;#39;&amp;#34;&lt;/span&gt; line.gnuplot
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;An example usage would be:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./line.sh CSL
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Which (given a few months of data) looked like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-12-how-to-graph-asx-data-with-gnuplot/2013-12-asx-csl-chart-example.png&#34;
	width=&#34;360&#34;
	height=&#34;216&#34;
	srcset=&#34;https://mike42.me/blog/2013-12-how-to-graph-asx-data-with-gnuplot/2013-12-asx-csl-chart-example_hu_1a12b8976554aa82.png 480w, https://mike42.me/blog/2013-12-how-to-graph-asx-data-with-gnuplot/2013-12-asx-csl-chart-example_hu_c3a94a8476e6ce18.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;ASX chart example&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;166&#34;
		data-flex-basis=&#34;400px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;file-list&#34;&gt;File list
&lt;/h2&gt;&lt;p&gt;If you follow this from start-to-finish, then you should have the following files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;data/
&lt;ul&gt;
&lt;li&gt;(Lots of zip files)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;plot/
&lt;ul&gt;
&lt;li&gt;CSL.dat&lt;/li&gt;
&lt;li&gt;CSL.pdf&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;txt/
&lt;ul&gt;
&lt;li&gt;(Lots of text files)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;asx-historic.db&lt;/li&gt;
&lt;li&gt;import.sh&lt;/li&gt;
&lt;li&gt;line.sh&lt;/li&gt;
&lt;li&gt;line.gnuplot&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>Installing Debian on a HP dm-1</title>
        <link>https://mike42.me/blog/2013-11-debian-7-on-the-hp-dm-1</link>
        <pubDate>Wed, 27 Nov 2013 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2013-11-debian-7-on-the-hp-dm-1</guid>
        <description>&lt;p&gt;Getting Debian working on different hardware is always a challenge. This week I attempted to install it on a &lt;strong&gt;HP Pavilion dm1 4306AU&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lspci&lt;/code&gt; shows that it has the following hardware:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:00.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 14h Processor Root Complex
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:01.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Wrestler [Radeon HD 7310]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:01.1 Audio device: Advanced Micro Devices, Inc. [AMD/ATI] Wrestler HDMI Audio
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:10.0 USB controller: Advanced Micro Devices, Inc. [AMD] FCH USB XHCI Controller (rev 03)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:11.0 SATA controller: Advanced Micro Devices, Inc. [AMD] FCH SATA Controller [AHCI mode]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:12.0 USB controller: Advanced Micro Devices, Inc. [AMD] FCH USB OHCI Controller (rev 11)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:12.2 USB controller: Advanced Micro Devices, Inc. [AMD] FCH USB EHCI Controller (rev 11)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:13.0 USB controller: Advanced Micro Devices, Inc. [AMD] FCH USB OHCI Controller (rev 11)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:13.2 USB controller: Advanced Micro Devices, Inc. [AMD] FCH USB EHCI Controller (rev 11)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:14.0 SMBus: Advanced Micro Devices, Inc. [AMD] FCH SMBus Controller (rev 14)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:14.2 Audio device: Advanced Micro Devices, Inc. [AMD] FCH Azalia Controller (rev 01)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:14.3 ISA bridge: Advanced Micro Devices, Inc. [AMD] FCH LPC Bridge (rev 11)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:14.4 PCI bridge: Advanced Micro Devices, Inc. [AMD] FCH PCI Bridge (rev 40)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:15.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] Hudson PCI to PCI bridge (PCIE port 0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:15.1 PCI bridge: Advanced Micro Devices, Inc. [AMD] Hudson PCI to PCI bridge (PCIE port 1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:18.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 12h/14h Processor Function 0 (rev 43)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:18.1 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 12h/14h Processor Function 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:18.2 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 12h/14h Processor Function 2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:18.3 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 12h/14h Processor Function 3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:18.4 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 12h/14h Processor Function 4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:18.5 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 12h/14h Processor Function 6
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:18.6 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 12h/14h Processor Function 5
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;00:18.7 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 12h/14h Processor Function 7
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;02:00.0 Network controller: Ralink corp. RT3290 Wireless 802.11n 1T/1R PCIe
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;02:00.1 Bluetooth: Ralink corp. RT3290 Bluetooth
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;06:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (rev 06)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The Debian installer worked fine, but it booted to a blank screen with a blinking underscore. Steps below to get a working machine.&lt;/p&gt;
&lt;h2 id=&#34;fix-graphics-and-wi-fi&#34;&gt;Fix graphics and Wi-Fi
&lt;/h2&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-11-debian-7-on-the-hp-dm-1/2013-12-hp-dm1-debian.jpg&#34;
	width=&#34;188&#34;
	height=&#34;250&#34;
	srcset=&#34;https://mike42.me/blog/2013-11-debian-7-on-the-hp-dm-1/2013-12-hp-dm1-debian_hu_e3e506d7b91fb139.jpg 480w, https://mike42.me/blog/2013-11-debian-7-on-the-hp-dm-1/2013-12-hp-dm1-debian_hu_58d5e86a0eb519f4.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Debian 7 running on a HP dm-1&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;75&#34;
		data-flex-basis=&#34;180px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;You need the nonfree firmware in &lt;code&gt;firmware-linux-nonfree&lt;/code&gt;. First select &amp;lsquo;recovery mode&amp;rsquo; from the boot menu.&lt;/p&gt;
&lt;p&gt;From the root terminal, &lt;code&gt;nano /etc/apt/sources.list&lt;/code&gt;, and add &lt;code&gt;non-free&lt;/code&gt;. Plug in a network cable, then:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get update &amp;amp;&amp;amp; apt-get install firmware-linux-nonfree firmware-ralink
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After a reboot, you can now get a working desktop and use Wi-Fi.&lt;/p&gt;
&lt;h2 id=&#34;the-beep-problem&#34;&gt;The beep problem
&lt;/h2&gt;&lt;p&gt;On shutdown, my computer gave a loud PC speaker beep, which could not be muted. The GNOME sound control doesn&amp;rsquo;t provide a volume bar for the PC speaker, so I installed the &lt;code&gt;gnome-alsamixer&lt;/code&gt; package, which has it:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-11-debian-7-on-the-hp-dm-1/2013-11-alsa-gnome.png&#34;
	width=&#34;798&#34;
	height=&#34;415&#34;
	srcset=&#34;https://mike42.me/blog/2013-11-debian-7-on-the-hp-dm-1/2013-11-alsa-gnome_hu_28a7efedae0d0f2b.png 480w, https://mike42.me/blog/2013-11-debian-7-on-the-hp-dm-1/2013-11-alsa-gnome_hu_4ea16855df0fdbd0.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Muting the PC speaker with gnome-alsa-mixer&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;192&#34;
		data-flex-basis=&#34;461px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Strangely, the beep returned after a few reboots, but was no longer as loud.&lt;/p&gt;
&lt;h2 id=&#34;brightness-keys&#34;&gt;Brightness keys
&lt;/h2&gt;&lt;p&gt;The brightness keys did not work originally, but upgrading to &amp;ldquo;testing&amp;rdquo; (&lt;em&gt;jessie&lt;/em&gt;) fixed this.&lt;/p&gt;
&lt;h2 id=&#34;overall&#34;&gt;Overall
&lt;/h2&gt;&lt;p&gt;This laptop requires two non-free packages to run, both of which are just firmware blobs.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Writing in Ancient Egyptian with HieroTeX</title>
        <link>https://mike42.me/blog/2013-10-writing-in-egyptian-with-hierotex</link>
        <pubDate>Mon, 14 Oct 2013 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2013-10-writing-in-egyptian-with-hierotex</guid>
        <description>&lt;p&gt;When I started learning Ancient Egyptian, I wanted to be able to type hieroglyphs alongside regular text, for printing translations. There is a package for the typesetting system LaTeX which does this, called &amp;ldquo;&lt;a href=&#34;http://webperso.iut.univ-paris8.fr/~rosmord/archives/&#34;&gt;HieroTeX&lt;/a&gt;&amp;rdquo;. It took me a while to figure out how to use it, but the results are top-notch:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-10-writing-in-egyptian-with-hierotex/2013-10-14-hierotex-example.png&#34;
	width=&#34;332&#34;
	height=&#34;80&#34;
	srcset=&#34;https://mike42.me/blog/2013-10-writing-in-egyptian-with-hierotex/2013-10-14-hierotex-example_hu_28e7c2e7b9eb72e2.png 480w, https://mike42.me/blog/2013-10-writing-in-egyptian-with-hierotex/2013-10-14-hierotex-example_hu_678dcea174d14c2a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Example of HieroTex output&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;415&#34;
		data-flex-basis=&#34;996px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Since I&amp;rsquo;ve installed this on a few computers, I&amp;rsquo;m writing up this blog post to make it easier for other Linux users who are trying to figure it out.&lt;/p&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation
&lt;/h2&gt;&lt;p&gt;This is tricky, because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There is no Debian package! Uh oh.&lt;/li&gt;
&lt;li&gt;Debian is phasing out &lt;code&gt;tetex&lt;/code&gt; in favour of &lt;code&gt;texlive&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;variables.mk&lt;/code&gt; file needs to be edited for the install to work (&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/files/variable.patch&#34; &gt;diff to apply&lt;/a&gt; / &lt;a class=&#34;link&#34; href=&#34;http://jungels.net/articles/diff-patch-ten-minutes.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;how to apply it&lt;/a&gt;). This is because the default installation target is the user&amp;rsquo;s home directory.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I put togethter this script, &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/files/hierotex-install-3.5.sh&#34; &gt;hierotex-install-3.5.sh&lt;/a&gt;, which will get a working &lt;code&gt;HieroTeX&lt;/code&gt; install on any recent version of Debian.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# Script to download and install HieroTeX on a Debian computer.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Use at your own risk.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Some packages you should install first:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 	apt-get install texlive make gcc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Get and extract the files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wget -c &lt;span class=&#34;s2&#34;&gt;&amp;#34;http://webperso.iut.univ-paris8.fr/~rosmord/archives/HieroTeX-3.5.tgz&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tar xvzf &lt;span class=&#34;s2&#34;&gt;&amp;#34;HieroTeX-3.5.tgz&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; HieroTeX &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wget -c &lt;span class=&#34;s2&#34;&gt;&amp;#34;http://webperso.iut.univ-paris8.fr/~rosmord/archives/HieroType1-3.1.4.tgz&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tar xvzf &lt;span class=&#34;s2&#34;&gt;&amp;#34;HieroType1-3.1.4.tgz&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Patch variable.mk to install for the whole system&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wget https://mike42.me/static/blog/files/variable.patch &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;patch variable.mk &amp;lt; variable.patch
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Run the installer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo make tetex-install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;a class=&#34;link&#34; href=&#34;http://www.filipvervloesem.be/egyptolinux/index.php?wiki=HieroTeX&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;This page&lt;/a&gt; is great, but the &lt;code&gt;variables.mk&lt;/code&gt; suggested for Debian/Ubuntu does not include the documentation folder, which will cause the installer to crash. It also suggests using &lt;code&gt;tetex&lt;/code&gt;, which will not exist in future Debian releases! This is probably fine if you are on a &lt;code&gt;.rpm&lt;/code&gt;-flavoured distro.&lt;/p&gt;
&lt;h2 id=&#34;how-to-use&#34;&gt;How to use
&lt;/h2&gt;&lt;p&gt;Firstly, you will need to know a little bit about the LaTeX typesetting system. See &lt;a class=&#34;link&#34; href=&#34;http://en.wikibooks.org/wiki/LaTeX&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;wikibooks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;HieroTeX accepts markup in &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/Manuel_de_Codage&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Manuel de Codage&lt;/a&gt; format, which you will either need to learn, or get a tool which helps you mark up text in it. This &lt;a class=&#34;link&#34; href=&#34;http://www.filipvervloesem.be/egyptolinux/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Linux for Egyptologists&lt;/a&gt; page has some excellent suggestions.&lt;/p&gt;
&lt;p&gt;The block of LaTeX code below is from my &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/tex-examples&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;tex-examples&lt;/a&gt; repo, and was used to generate the image of Tutankhamun&amp;rsquo;s cartouche above.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-latex&#34; data-lang=&#34;latex&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\documentclass&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;[a4paper]&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;article&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\usepackage&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;hiero&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\usepackage&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;egypto&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\begin&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;document&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;\section*&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;Egyptian hieroglyph example&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;\begin&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;hieroglyph&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;zA ra &amp;lt; i-mn:n-t-G43-t-S34 HqA-iwn-Sma &amp;gt;&lt;span class=&#34;k&#34;&gt;\end&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;hieroglyph&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;\\&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;\em&lt;/span&gt; Tutankhamun Hekaiunushema&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;\\&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	Living Image of Amun, ruler of Upper Heliopolis
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;\end&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;{&lt;/span&gt;document&lt;span class=&#34;nb&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To build the file, you need to filter it through &lt;code&gt;sesh&lt;/code&gt; command. Something like this would work:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat hierotex-example.tex | sesh &amp;gt; hierotex-example-2.tex
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;latex hierotex-example-2.tex
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The actual example &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/tex-examples/blob/master/hierotex/Makefile&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;uses a Makefile&lt;/a&gt; to do this.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update May 2016&lt;/strong&gt;: The original website for HieroTeX has gone offline, but is available via the Internet Archive: &lt;a class=&#34;link&#34; href=&#34;https://web.archive.org/web/20120930234009/http://webperso.iut.univ-paris8.fr/~rosmord/archives/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;webperso.iut.univ-paris8.fr/~rosmord/archives/&lt;/a&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Transforming between SQL dialects</title>
        <link>https://mike42.me/blog/2013-10-transforming-sql</link>
        <pubDate>Wed, 02 Oct 2013 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2013-10-transforming-sql</guid>
        <description>&lt;p&gt;I recently found myself Googling for some data wizardry. I have a web app which holds some data that I want to work with locally, and the RDBMS requirements are a little bit incompatible.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-10-transforming-sql/2013-10-sql-transformation.png&#34;
	width=&#34;367&#34;
	height=&#34;83&#34;
	srcset=&#34;https://mike42.me/blog/2013-10-transforming-sql/2013-10-sql-transformation_hu_16657ca2450aaee3.png 480w, https://mike42.me/blog/2013-10-transforming-sql/2013-10-sql-transformation_hu_f742bdc1f0c09204.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;442&#34;
		data-flex-basis=&#34;1061px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Unfortunately, neither &lt;a class=&#34;link&#34; href=&#34;https://gist.github.com/esperlu/943776&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this impressive &lt;code&gt;sed&lt;/code&gt; script&lt;/a&gt; nor this &lt;a class=&#34;link&#34; href=&#34;https://gist.github.com/sferik/265790&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;eloquent mix of &lt;code&gt;sed&lt;/code&gt;, ruby and perl&lt;/a&gt; could do this with fewer than 100 syntax errors in the output, so I had to get creative.&lt;/p&gt;
&lt;p&gt;This blog post is just some quick notes on what I&amp;rsquo;ve learned.&lt;/p&gt;
&lt;h2 id=&#34;simplify-the-problem&#34;&gt;Simplify the problem
&lt;/h2&gt;&lt;p&gt;I decided to convert the structure to SQLite manually, as it is not likely to change. The parts you will need to convert often (thousands of &lt;code&gt;INSERT&lt;/code&gt; statements) are the parts which are more important to have a script for. The extra &lt;code&gt;mysqldump&lt;/code&gt; options for getting the data only, without nasty backticks were:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--compatible=ansi --skip-extended-insert --compact --no-create-info
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;use-sed&#34;&gt;Use &lt;code&gt;sed&lt;/code&gt;
&lt;/h2&gt;&lt;p&gt;I used &lt;code&gt;sed&lt;/code&gt; to fix the escaping. MySQL escapes single quotes with &lt;code&gt;\&#39;&lt;/code&gt;, and double quotes with &lt;code&gt;\&amp;quot;&lt;/code&gt; but SQLite uses &lt;code&gt;&#39;&#39;&lt;/code&gt; and &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt;. This one-liner made the conversion:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sed -e &amp;#34;s/\&amp;#39;/&amp;#39;&amp;#39;/g&amp;#34; -e &amp;#39;s/\&amp;#34;/&amp;#34;/g&amp;#39; db.sql &amp;gt; db.sqlite
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The resulting file could be imported directly into SQLite, provided that the tables had already been defined.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Patton CLI commands</title>
        <link>https://mike42.me/blog/2013-09-patton-cli-commands</link>
        <pubDate>Mon, 30 Sep 2013 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2013-09-patton-cli-commands</guid>
        <description>&lt;p&gt;Patton makes gateways to connect computer networks to telephone networks. They are extremely configurable, though you do need to put a bit of effort into figuring out how they work.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-09-patton-cli-commands/2013-09-patton.png&#34;
	width=&#34;300&#34;
	height=&#34;292&#34;
	srcset=&#34;https://mike42.me/blog/2013-09-patton-cli-commands/2013-09-patton_hu_5edcbdf4f0fa5aa9.png 480w, https://mike42.me/blog/2013-09-patton-cli-commands/2013-09-patton_hu_96528fabcb6cf73a.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Patton SN4114 and SN4120&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;102&#34;
		data-flex-basis=&#34;246px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Setting the admin password via the web interface hasn&amp;rsquo;t worked on any of the 5 SmartNodes which I&amp;rsquo;ve used, but rather than try a firmware upgrade, I thought I&amp;rsquo;d try via the CLI.&lt;/p&gt;
&lt;p&gt;Whilst I was logged in, I noticed that they all support SNMP, which I also can&amp;rsquo;t find out how to enable via the web interface.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;enable
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    configure
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        administrator &amp;lt;username&amp;gt; password &amp;lt;password&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        snmp community &amp;lt;public&amp;gt; ro
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        copy running-config startup-config
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        exit
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    exit
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;exit
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;why-snmp&#34;&gt;Why SNMP?
&lt;/h2&gt;&lt;p&gt;SNMP lets you check just about anything. In my case, I use it to find out if ISDN lines are down, via the &lt;code&gt;check_snmp&lt;/code&gt; plugin for &lt;a class=&#34;link&#34; href=&#34;https://www.icinga.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Icinga&lt;/a&gt;.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Infinite loop in a Makefile</title>
        <link>https://mike42.me/blog/2013-09-infinite-loop-in-a-makefile</link>
        <pubDate>Fri, 27 Sep 2013 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2013-09-infinite-loop-in-a-makefile</guid>
        <description>&lt;p&gt;I had to kick myself for writing this bug into a Makefile today. I am writing it down so that I remember to use &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;, and not &lt;code&gt;;&lt;/code&gt; next time.&lt;/p&gt;
&lt;p&gt;The Makefile had this target in it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;clean:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	cd folder; \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		make clean
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	rm -f file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The problem here is that the statement &lt;code&gt;cd folder; make clean&lt;/code&gt; counts as one &amp;ldquo;line&amp;rdquo;, and &lt;code&gt;make&lt;/code&gt; won&amp;rsquo;t notice a problem (and stop) until that line has executed and returns non-zero.&lt;/p&gt;
&lt;p&gt;Unfortunately, in the case that the directory does not exist, this script had a chance to call &lt;code&gt;make clean&lt;/code&gt; without changing directory. It then calls itself and becoming stuck in an infinite loop.&lt;/p&gt;
&lt;p&gt;So lesson learned, this is why Makefiles should be littered with the &amp;ldquo;and&amp;rdquo; operator.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;clean:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	cd folder &amp;amp;&amp;amp; \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		make clean
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	rm -f file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>Loading Asterisk CDR into a database</title>
        <link>https://mike42.me/blog/2013-09-loading-asterisk-cdr-into-a-database</link>
        <pubDate>Fri, 27 Sep 2013 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2013-09-loading-asterisk-cdr-into-a-database</guid>
        <description>&lt;p&gt;In the interests of accurate accounting, Asterisk creates a Master.csv, logging all calls and a few things about them.&lt;/p&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://wiki.asterisk.org/wiki/display/AST/CDR&amp;#43;Fields&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;This page&lt;/a&gt; on wiki.asterisk.org has a good breakdown of what all the fields mean.&lt;/p&gt;
&lt;p&gt;I put together this MySQL table so that the data can be processed for data-analysis, accounting, or whatever it is that the data is needed for.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;-- Code to create MySQL table for Asterisk CDR data
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;-- Field descriptions from:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;--   https://wiki.asterisk.org/wiki/display/AST/CDR+Fields
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;CREATE&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;TABLE&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cdr&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;accountcode&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;VARCHAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;256&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COMMENT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;What account number to use, (string, 20 characters)&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;VARCHAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COMMENT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;CallerID number&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dst&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;VARCHAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COMMENT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Destination extension&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dcontext&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;VARCHAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COMMENT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Destination context&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;clid&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;VARCHAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COMMENT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;CallerID with text&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;channel&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;VARCHAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COMMENT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Channel used&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dstchannel&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;VARCHAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COMMENT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Destination channel if appropriate&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lastapp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;VARCHAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COMMENT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Last application if appropriate&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lastdata&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;VARCHAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COMMENT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Last application data (arguments)&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tsstart&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;DATETIME&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COMMENT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Start of call (date/time)&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tsanswer&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;DATETIME&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COMMENT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Answer of call (date/time)&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tsend&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;DATETIME&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COMMENT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;End of call (date/time)&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;duration&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;INT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;11&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COMMENT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Total time in system, in seconds (integer), from dial to hangup&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;billsec&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;INT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;11&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COMMENT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Total time call is up, in seconds (integer), from answer to hangup&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;disposition&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ENUM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;ANSWERED&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;NO ANSWER&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;BUSY&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COMMENT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;What happened to the call&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;amaflags&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ENUM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;DOCUMENTATION&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;BILL&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;IGNORE&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COMMENT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;What flags to use, specified on a per channel basis like accountcode.&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uniqueid&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;VARCHAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COMMENT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Unique Channel Identifier&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;userfield&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;VARCHAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;256&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COMMENT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;user field: A user-defined field, maximum 255 characters&amp;#39;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The second-last field is not present on all installations, but it is on mine. The version I&amp;rsquo;m on is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;asterisk:~# asterisk -V
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Asterisk 1.8.10.1~dfsg-1ubuntu1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are several methods to import CSV data into MySQL. In this case I used &lt;code&gt;LOAD DATA INFILE&lt;/code&gt;.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>How to liberate your myki data</title>
        <link>https://mike42.me/blog/2013-09-how-to-liberate-your-myki-data</link>
        <pubDate>Wed, 04 Sep 2013 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2013-09-how-to-liberate-your-myki-data</guid>
        <description>&lt;p&gt;myki is the public transport ticketing system in Melbourne. If you register your myki, you can view the usage history online. Unfortunately, you are limited to paging through HTML, or downloading a PDF.&lt;/p&gt;
&lt;p&gt;This post will show you how to get your myki history into a CSV file on a GNU/Linux computer, so that you can analyse it with your favourite spreadsheet/database program.&lt;/p&gt;
&lt;h2 id=&#34;get-your-data-as-pdfs&#34;&gt;Get your data as PDFs
&lt;/h2&gt;&lt;p&gt;Firstly, you need to register your myki, log in, and export your history. The web interface seemed to give you the right data if you chose blocks of 1 month.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-09-how-to-liberate-your-myki-data/2013-09-myki-select-date.png&#34;
	width=&#34;466&#34;
	height=&#34;171&#34;
	srcset=&#34;https://mike42.me/blog/2013-09-how-to-liberate-your-myki-data/2013-09-myki-select-date_hu_aa3d05dbcbe3d4cf.png 480w, https://mike42.me/blog/2013-09-how-to-liberate-your-myki-data/2013-09-myki-select-date_hu_5c0432877d4bf5e0.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;272&#34;
		data-flex-basis=&#34;654px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Once you do this, organise these into a folder filled with statements.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-09-how-to-liberate-your-myki-data/2013-09-myki-statements.png&#34;
	width=&#34;300&#34;
	height=&#34;103&#34;
	srcset=&#34;https://mike42.me/blog/2013-09-how-to-liberate-your-myki-data/2013-09-myki-statements_hu_f00c70f980682c2e.png 480w, https://mike42.me/blog/2013-09-how-to-liberate-your-myki-data/2013-09-myki-statements_hu_9348f48f286d6cf8.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;291&#34;
		data-flex-basis=&#34;699px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;You need the &lt;code&gt;pdftotext&lt;/code&gt; utility to go on.  In debian, this is in the &lt;tt&gt;&lt;a class=&#34;link&#34; href=&#34;http://packages.debian.org/stable/poppler-utils&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;poppler-utils&lt;/a&gt;&lt;/tt&gt; package.&lt;/p&gt;
&lt;p&gt;The manual steps below run you through how to extract the data, and at the bottom of the screen there are some scripts I&amp;rsquo;ve put together to do this automatically.&lt;/p&gt;
&lt;h2 id=&#34;manual-steps-to-extract-your-data&#34;&gt;Manual steps to extract your data
&lt;/h2&gt;&lt;p&gt;These steps are basically a crash course in &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/Data_scraping&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;scraping&lt;/a&gt; PDF files.&lt;/p&gt;
&lt;p&gt;To convert all of the PDF&amp;rsquo;s to text, run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;for i in *.pdf; do pdftotext -layout -nopgbrk $i; done
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This preserves the line-based layout. The next step is to filter out the lines which don&amp;rsquo;t contain data. Each line we&amp;rsquo;re interested in begins with a date, followed by the word &amp;ldquo;Touch On&amp;rdquo;, &amp;ldquo;Touch Off&amp;rdquo;, or &amp;ldquo;Top Up&amp;rdquo;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;18/08/2013 13:41:20   T...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can filter all of the text files using &lt;code&gt;grep&lt;/code&gt;, and a regex to match this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat *.txt &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep &lt;span class=&#34;s2&#34;&gt;&amp;#34;^[0-3][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] *T&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The output looks like:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-09-how-to-liberate-your-myki-data/2013-09-myki-grep.png&#34;
	width=&#34;300&#34;
	height=&#34;135&#34;
	srcset=&#34;https://mike42.me/blog/2013-09-how-to-liberate-your-myki-data/2013-09-myki-grep_hu_ae053b251a55442.png 480w, https://mike42.me/blog/2013-09-how-to-liberate-your-myki-data/2013-09-myki-grep_hu_68cfd8ea1028fd4.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;222&#34;
		data-flex-basis=&#34;533px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;So what are we looking at?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;One row per line&lt;/li&gt;
&lt;li&gt;Fields delimited by multiple spaces&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To collapse every double-space into a tab, we use &lt;code&gt;unexpand&lt;/code&gt;. Then, to collapse duplicate tabs, we use &lt;code&gt;tr&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat filtered-data.txt &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; unexpand -t &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; tr -s &lt;span class=&#34;s1&#34;&gt;&amp;#39;\t&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, some fields need to be quoted, and tabs need to be converted to CSV. The PHP script below will do that step.&lt;/p&gt;
&lt;h2 id=&#34;scripts-to-get-your-data&#34;&gt;Scripts to get your data
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;myki2csv.sh&lt;/code&gt;&lt;/strong&gt; is a script which performs the above manual steps:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# Convert myki history from PDF to CSV&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#    (c) Michael Billington &amp;lt; michael.billington@gmail.com &amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#    MIT Licence&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;hash&lt;/span&gt; pdftotext &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;hash&lt;/span&gt; unexpand &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pdftotext -layout -nopgbrk &lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt; - &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    grep &lt;span class=&#34;s2&#34;&gt;&amp;#34;^[0-3][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] *T&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    unexpand -t2 &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    tr -s &lt;span class=&#34;s1&#34;&gt;&amp;#39;\t&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    ./tab2csv.php &amp;gt; &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;%.pdf&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;.csv
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;tab2csv.php&lt;/code&gt;&lt;/strong&gt; is called at the end of the above script, to turn the result into a well-formed CSV file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#!/usr/bin/env php
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;lt;?php
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/* Generate well-formed CSV from dodgy tab-delimitted data
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    (c) Michael Billington &amp;lt; michael.billington@gmail.com &amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    MIT Licence */
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$in = fopen(&amp;#34;php://stdin&amp;#34;, &amp;#34;r&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$out = fopen(&amp;#34;php://stdout&amp;#34;, &amp;#34;w&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;while($line = fgets($in)) {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    $a = explode(&amp;#34;\t&amp;#34;, $line);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    foreach($a as $key =&amp;gt; $value) {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        $a[$key]=trim($value);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        /* Quote out &amp;#34;,&amp;#34;, and escape &amp;#34;&amp;#34; */
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        if(!(strpos($value, &amp;#34;\&amp;#34;&amp;#34;) === false &amp;amp;&amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                strpos($value, &amp;#34;,&amp;#34;) === false)) {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            $a[$key] = &amp;#34;\&amp;#34;&amp;#34;.str_replace(&amp;#34;\&amp;#34;&amp;#34;, &amp;#34;\&amp;#34;\&amp;#34;&amp;#34;, $a[$key]).&amp;#34;\&amp;#34;&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    $line = implode(&amp;#34;,&amp;#34;, $a) . &amp;#34;\r\n&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    fwrite($out, $line);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;invocation&#34;&gt;Invocation
&lt;/h2&gt;&lt;p&gt;Call script on a single &lt;code&gt;foo.pdf&lt;/code&gt; to get &lt;code&gt;foo.csv&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./myki2csv.sh foo.pdf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Convert all PDF&amp;rsquo;s to CSV and then join them:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; i in *.pdf&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; ./myki2csv.sh &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tac *.csv &amp;gt; my-myki-data.csv
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;importing-into-libreoffice&#34;&gt;Importing into LibreOffice
&lt;/h2&gt;&lt;p&gt;The first field must be marked as a DD/MM/YYYY date, and the &amp;ldquo;zones&amp;rdquo; need to be marked as text (so that &amp;ldquo;1/2&amp;rdquo; isn&amp;rsquo;t treated as a fraction!)&lt;/p&gt;
&lt;p&gt;These are my import settings:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-09-how-to-liberate-your-myki-data/2013-09-myki-import.png&#34;
	width=&#34;797&#34;
	height=&#34;600&#34;
	srcset=&#34;https://mike42.me/blog/2013-09-how-to-liberate-your-myki-data/2013-09-myki-import_hu_64220dbd613dda96.png 480w, https://mike42.me/blog/2013-09-how-to-liberate-your-myki-data/2013-09-myki-import_hu_1500a98db5907b3c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;132&#34;
		data-flex-basis=&#34;318px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Happy data analysis!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 2013-09-18:&lt;/strong&gt; The &lt;code&gt;-nopgbrk&lt;/code&gt; option was added to the above instructions, to prevent page break characters causing &lt;code&gt;grep&lt;/code&gt; to skip one valid line per page&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 2014-05-04:&lt;/strong&gt; The code for the above, as well as &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2014-03-importing-myki-data-into-gnucash&#34; &gt;this follow-up post&lt;/a&gt; are now available &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/myki-import&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;on GitHub&lt;/a&gt;.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Why you should disable IPv6 on Windows</title>
        <link>https://mike42.me/blog/2013-08-why-you-should-disable-ipv6-on-windows</link>
        <pubDate>Fri, 09 Aug 2013 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2013-08-why-you-should-disable-ipv6-on-windows</guid>
        <description>&lt;p&gt;This post is mainly a response to an article which I stumbled across today:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;http://www.howfunky.com/2011/02/why-you-should-not-disable-ipv6-for.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Why you should NOT disable IPv6 for Windows 7 or Server 2008R2&lt;/a&gt; (referencing &lt;a class=&#34;link&#34; href=&#34;http://technet.microsoft.com/en-us/magazine/2009.07.cableguy.aspx&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this technet article&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is not (in my opinion) good advice to follow just at the moment.&lt;/p&gt;
&lt;p&gt;If you are running any Windows computer on an un-trusted network, then it is probably wide open to &lt;a class=&#34;link&#34; href=&#34;http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2010-4669&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;CVE-2010-4669&lt;/a&gt;. This means that a few thousand dodgy ICMPv6 packets could fill up its memory until it keels over and needs to be rebooted.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not an advocate of Windows on servers, but it exists and can be made to crash less. If you don&amp;rsquo;t need IPv6, because you are behind an IPv4 NAT for example, you can just switch it off and bypass Microsoft&amp;rsquo;s poorly designed implementation altogether. To that end, &lt;a class=&#34;link&#34; href=&#34;http://support.serverintellect.com/KB/a135/how-to-disable-ipv6-on-windows-server-2008.aspx&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;here is a nice article&lt;/a&gt; that will get you deploying &lt;code&gt;.reg&lt;/code&gt; files for that in a few minutes.&lt;/p&gt;
&lt;p&gt;This is easy and I would recommend it. Contrary to the article above, your computer will work fine on an IPv4 network without IPv6. If disabling IPv6 breaks some application, then it probably wouldn&amp;rsquo;t have worked properly on your network anyway. What&amp;rsquo;s important is that the computer works!&lt;/p&gt;
&lt;p&gt;A solid Windows firewall configuration will also solve this, but involves leaving the vulnerable stack running. This is a decent security compromise, as it assumes that you will actually cover every possible attack scenario in your firewall rules.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>QJoyPad coolness</title>
        <link>https://mike42.me/blog/2013-06-qjoypad-coolness</link>
        <pubDate>Fri, 07 Jun 2013 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2013-06-qjoypad-coolness</guid>
        <description>&lt;p&gt;A while back I bought a USB gamepad from for controlling a &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/missile&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;foam missile launcher&lt;/a&gt;, and recently decided to re-purpose it for controlling a GNU/Linux computer. After all VLC is great, but plugging in a keyboard is not so great!&lt;/p&gt;
&lt;p&gt;The gamepad imitates a Super Nintendo controller in terms of size and button placement, and is apparently a USB joystick in disguise. From &lt;code&gt;lsusb&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Bus 003 Device 004: ID 0079:0011 DragonRise Inc. Gamepad
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The only packaged program for mapping this to keyboard events in Debian was &lt;code&gt;joy2key&lt;/code&gt;. It was too cryptic for me to figure out in under 5 minutes, so I looked for alternatives. Google turned up &lt;code&gt;xjoypad&lt;/code&gt;, &lt;code&gt;jkeys&lt;/code&gt; and &lt;code&gt;jscal&lt;/code&gt; as suggestions, but &lt;a class=&#34;link&#34; href=&#34;http://qjoypad.sourceforge.net/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;QJoypad&lt;/a&gt; looked the most promising, and had an interface which matched my expectations of how this type of program works:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-06-qjoypad-coolness/2013-06-07-qjoypad.png&#34;
	width=&#34;387&#34;
	height=&#34;420&#34;
	srcset=&#34;https://mike42.me/blog/2013-06-qjoypad-coolness/2013-06-07-qjoypad_hu_2a19b736e7d485f3.png 480w, https://mike42.me/blog/2013-06-qjoypad-coolness/2013-06-07-qjoypad_hu_b6b2f32aeeda89d2.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;92&#34;
		data-flex-basis=&#34;221px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;To compile it, you need the QT development libraries, and an X library called &lt;code&gt;libxtst-dev&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The profile in the screenshot (called &amp;ldquo;VLC&amp;rdquo;) controls the mouse, pauses, adjusts volume, and toggles fullscreen. It works well enough for media and web browsing, as long as you don&amp;rsquo;t need to type anything!&lt;/p&gt;
&lt;p&gt;Bugs I noticed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Can&amp;rsquo;t set a button to Ctrl + &amp;lt; Key &amp;gt;, only the key on its own.&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>Backing up from a hosting provider</title>
        <link>https://mike42.me/blog/2013-05-backing-up-from-a-hosting-provider</link>
        <pubDate>Fri, 03 May 2013 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2013-05-backing-up-from-a-hosting-provider</guid>
        <description>&lt;p&gt;Backups are great, and they&amp;rsquo;re not rocket science. I&amp;rsquo;m writing up how I do backups, not because I think it&amp;rsquo;s a cool or unique setup (it&amp;rsquo;s not), but to highlight how effective a simple solution can be.&lt;/p&gt;
&lt;p&gt;We use &lt;a class=&#34;link&#34; href=&#34;http://rsync.samba.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;rsync&lt;/a&gt; to take a local copy of whatever is on our web host without wasting bandwidth downloading files that aren&amp;rsquo;t needed. The layout looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-05-backing-up-from-a-hosting-provider/2013-05-04-backup.png&#34;
	width=&#34;567&#34;
	height=&#34;208&#34;
	srcset=&#34;https://mike42.me/blog/2013-05-backing-up-from-a-hosting-provider/2013-05-04-backup_hu_f09298773a98ba2d.png 480w, https://mike42.me/blog/2013-05-backing-up-from-a-hosting-provider/2013-05-04-backup_hu_a3cec0de7bc5d191.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;272&#34;
		data-flex-basis=&#34;654px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Our hosting provider is accessible via &lt;code&gt;ssh&lt;/code&gt;, and the backup box we use is a &lt;a class=&#34;link&#34; href=&#34;http://www.raspberrypi.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Raspberry Pi model B&lt;/a&gt;, costing approximately 50 AUD to get running.&lt;/p&gt;
&lt;h2 id=&#34;on-the-server&#34;&gt;On the server
&lt;/h2&gt;&lt;p&gt;On the server, I back up databases with &lt;code&gt;mysqldump&lt;/code&gt;. To do this, you need to enter user details into a &lt;code&gt;.my.cnf&lt;/code&gt; file, and then something like this will do the trick:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# Remove old dump&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rm -f database.sql.gz
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Dump and compress database&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mysqldump -h sql.example.com --all-databases &amp;gt; database.sql
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gzip database.sql
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The above script is called &lt;code&gt;database-dump.sh&lt;/code&gt;, and is called from the backup box, to dump the databases to a file before grabbing all the files.&lt;/p&gt;
&lt;h2 id=&#34;on-the-backup-box&#34;&gt;On the backup box
&lt;/h2&gt;&lt;p&gt;First, a script to get the files. I use password-less login with &lt;code&gt;ssh-copy-id&lt;/code&gt; so that this works non-interactively:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# Update the database dump&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ssh user@host.example.com &lt;span class=&#34;s1&#34;&gt;&amp;#39;./database-dump.sh&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Get files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rsync -avz --delete-during user@host.example.com:/home/user .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We save a copy of the files at this date in a dated archive, so we can back-date to find deleted things. At the end of the above script:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir -p archive
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;now&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;date +&lt;span class=&#34;s2&#34;&gt;&amp;#34;%Y-%m-%d&amp;#34;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tar -czf archive/backup-&lt;span class=&#34;nv&#34;&gt;$now&lt;/span&gt;.tar.gz user
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There aren&amp;rsquo;t a huge number of changes to record daily, so I get &lt;code&gt;cron&lt;/code&gt; to run the above script weekly on the backup box. Read &lt;code&gt;man crontab&lt;/code&gt; for how to do this.&lt;/p&gt;
&lt;h2 id=&#34;the-elephant-in-the-room&#34;&gt;The elephant in the room
&lt;/h2&gt;&lt;p&gt;If you think you shouldn&amp;rsquo;t be doing backups, you&amp;rsquo;re wrong.&lt;/p&gt;
&lt;p&gt;I just want to wrap up this blog post by addressing some of the most common &lt;em&gt;rationalisations&lt;/em&gt; I&amp;rsquo;ve seen for skipping over this.&lt;/p&gt;
&lt;h3 id=&#34;excuse-1-trust&#34;&gt;Excuse 1: Trust
&lt;/h3&gt;&lt;p&gt;This is the idea that whoever has the data won&amp;rsquo;t lose it.&lt;/p&gt;
&lt;p&gt;Our host is pretty good, but their terms of service state that they won&amp;rsquo;t be responsible for any data loss. Even providers which have support agreements can make mistakes. You&amp;rsquo;ll also be able to work faster if you&amp;rsquo;re not paranoid about any mistake being unrecoverable.&lt;/p&gt;
&lt;h3 id=&#34;excuse-2-expense&#34;&gt;Excuse 2: Expense
&lt;/h3&gt;&lt;p&gt;This is the idea that backup is a nice idea but &lt;em&gt;not worth it&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I think that underlying this excuse is an ingrained idea that a backup system must have a particular set of (expensive) characteristics, when in reality a scheduled &lt;code&gt;rsync&lt;/code&gt; is an improvement over no backup at all.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s dirt cheap, you can learn to do it yourself, and once running it requires virtually no administration.&lt;/p&gt;
&lt;h3 id=&#34;excuse-3-raid&#34;&gt;Excuse 3: RAID
&lt;/h3&gt;&lt;p&gt;Lastly, the idea that after investing in RAID, or some other kind of redundancy, you don&amp;rsquo;t need backups.&lt;/p&gt;
&lt;p&gt;If you accidentally delete something, or notice that some your files have been tampered with, then RAID will not help you. If there is a problem (eg. fire) at the hosting location, then you will be &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/up_shit_creek&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;in trouble&lt;/a&gt; regardless of disk redundancy.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>&#34;Hello World&#34; in python (with curses)</title>
        <link>https://mike42.me/blog/2013-04-hello-world-in-python-with-curses</link>
        <pubDate>Tue, 30 Apr 2013 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2013-04-hello-world-in-python-with-curses</guid>
        <description>&lt;p&gt;I use the &lt;a class=&#34;link&#34; href=&#34;http://www.tldp.org/HOWTO/NCURSES-Programming-HOWTO/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;ncurses&lt;/a&gt; library a lot, and decided to have a shot at python today.&lt;/p&gt;
&lt;p&gt;Thankfully they have a &lt;a class=&#34;link&#34; href=&#34;http://docs.python.org/2/library/curses.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;great curses module&lt;/a&gt;, so I started out with a &amp;ldquo;hello world&amp;rdquo; program that looked like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;ch&#34;&gt;#!/usr/bin/env python&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;curses&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;scr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;curses&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;initscr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;scr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;keypad&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;curses&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;noecho&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;scr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;addstr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;hello world&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;scr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;refresh&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;scr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;getch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;curses&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;endwin&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>Debian &amp; XFCE quirks on Toshiba NB550D</title>
        <link>https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d</link>
        <pubDate>Fri, 01 Mar 2013 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d</guid>
        <description>&lt;p&gt;Today I re-installed Debian wheezy on my &lt;a class=&#34;link&#34; href=&#34;http://apcmag.com/the-netbook-to-buy-toshiba-nb550d.htm&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Toshiba netbook&lt;/a&gt; and realised how useful it might be to collate the hurdles into one tidy reference blog post (to save looking everything up next time).&lt;/p&gt;
&lt;p&gt;This just covers everything I had to configure or work around to get a working setup.&lt;/p&gt;
&lt;h2 id=&#34;install--hardware-issues&#34;&gt;Install &amp;amp; hardware issues
&lt;/h2&gt;&lt;p&gt;From linux, use &lt;code&gt;dd&lt;/code&gt; to write your disk image onto a flash drive:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dd &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;debian-wheezy-DI-rc1-amd64-netinst.iso &lt;span class=&#34;nv&#34;&gt;of&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/dev/sdX &lt;span class=&#34;nv&#34;&gt;bs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;4M
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you don&amp;rsquo;t know your flash drive device, then locate &amp;lsquo;Disk Utility&amp;rsquo; or use &lt;code&gt;sudo fdisk -l&lt;/code&gt; and choose the likely candidate.&lt;/p&gt;
&lt;p&gt;Now boot up the netbook. If you&amp;rsquo;ve disabled the splash screen, then F12 will get you a boot menu and F2 will let you enable USB booting (if you don&amp;rsquo;t see the flash drive).&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-bootmenu.jpg&#34;
	width=&#34;350&#34;
	height=&#34;197&#34;
	srcset=&#34;https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-bootmenu_hu_dcc62e3cfb72c9f7.jpg 480w, https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-bootmenu_hu_26a7799dc7cc4ea0.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The installer gives you a warning about needing non-free firmware. You can safely ignore this, it&amp;rsquo;s just bluetooth.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-firmware.jpg&#34;
	width=&#34;350&#34;
	height=&#34;119&#34;
	srcset=&#34;https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-firmware_hu_58b354a843db07db.jpg 480w, https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-firmware_hu_98977970601666d5.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;294&#34;
		data-flex-basis=&#34;705px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;When you get the option to, &lt;strong&gt;Install openssh&lt;/strong&gt;. You will have graphics issues later, and you will not be able to proceed without some other way to log in.&lt;/p&gt;
&lt;p&gt;Follow the installer as usual, and boot into the new system.&lt;/p&gt;
&lt;h3 id=&#34;graphics&#34;&gt;Graphics
&lt;/h3&gt;&lt;p&gt;From GNOME, everything initially worked okay out of the box for me, but logging out would predictably corrupt the graphics like so:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-distort-large.jpg&#34;
	width=&#34;1024&#34;
	height=&#34;624&#34;
	srcset=&#34;https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-distort-large_hu_b30e20ed5fdc3739.jpg 480w, https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-distort-large_hu_5c690add5c4268a3.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;164&#34;
		data-flex-basis=&#34;393px&#34;
	
&gt;
&lt;img src=&#34;https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-distort2-large.jpg&#34;
	width=&#34;900&#34;
	height=&#34;675&#34;
	srcset=&#34;https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-distort2-large_hu_2e52d3328d0dbd.jpg 480w, https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-distort2-large_hu_862b5a6b6f31d7ba.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pro-tip(TM)&lt;/strong&gt;: Write down your IP address before this happens and follow the rest of the steps via ssh.&lt;/p&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;http://wiki.debian.org/AtiHowTo&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;These steps&lt;/a&gt; on the Debian wiki suggest getting &lt;code&gt;xserver-xorg-video-radeon&lt;/code&gt; and &lt;code&gt;xserver-xorg-video-ati&lt;/code&gt;, but they are already installed (and &lt;code&gt;xserver-xorg-video-radeonhd&lt;/code&gt; does not appear to exist in wheezy). The free firmware also didn&amp;rsquo;t work for me:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@mikebook:~# apt-get install firmware-linux-free
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So it looks like we need &lt;code&gt;firmware-linux-nonfree&lt;/code&gt;, which means we need to allow non-free packages. Edit the end of each line in &lt;code&gt;/etc/apt/sources.list&lt;/code&gt; to add &lt;code&gt;contrib&lt;/code&gt; and &lt;code&gt;non-free&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-sources-list.jpg&#34;
	width=&#34;687&#34;
	height=&#34;98&#34;
	srcset=&#34;https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-sources-list_hu_b31b55de4fa82522.jpg 480w, https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-sources-list_hu_56295e9c7f90af5f.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;701&#34;
		data-flex-basis=&#34;1682px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;After this, update your package list, install the non-free firmware, and restart X (rebooting is shown here but not really necessary):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get update
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install firmware-linux-nonfree
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;reboot
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next time you log in, GNOME will report that it is running in full-bloat mode, which is a good sign. If you still have issues, then the output of &lt;code&gt;lspci&lt;/code&gt; is what you need to google:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;02:00.0 VGA compatible controller: Advanced Micro Devices [AMD] nee ATI RV710 [Radeon HD 4350] (prog-if 00 [VGA controller])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;touchpad--two-finger-scroll&#34;&gt;Touchpad / two-finger scroll
&lt;/h3&gt;&lt;p&gt;The Laptop&amp;rsquo;s Synaptics touchpad will work just fine on the default settings. I only wrote this up because the version of XFCE in wheezy has no options for tapping, two-finger scroll, or other fancy things (unlike the &lt;a class=&#34;link&#34; href=&#34;http://docs.xfce.org/xfce/xfce4-settings/mouse&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;screenshots&lt;/a&gt; on xfce.org).&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-xfce-mouse.jpg&#34;
	width=&#34;447&#34;
	height=&#34;459&#34;
	srcset=&#34;https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-xfce-mouse_hu_6ec6c46b40a6bf29.jpg 480w, https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-xfce-mouse_hu_5307c1446c9e51f2.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;97&#34;
		data-flex-basis=&#34;233px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;GNOME will let you set up per-user mouse preferences, but these don&amp;rsquo;t affect gdm (the login screen), so you can&amp;rsquo;t tap the login buttons (how annoying!)&lt;/p&gt;
&lt;p&gt;The solution is to configure the mouse using Xorg&amp;rsquo;s configuration. The Debian &lt;a class=&#34;link&#34; href=&#34;http://wiki.debian.org/SynapticsTouchpad&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;wiki page&lt;/a&gt; on the topic gives an example file to dump in &lt;code&gt;/etc/X11/xorg.conf.d/&lt;/code&gt;. I swapped the &lt;code&gt;TapButton2&lt;/code&gt; and &lt;code&gt;TapButton3&lt;/code&gt; values to get two-finger right-click:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Section &amp;#34;InputClass&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        Identifier      &amp;#34;Touchpad&amp;#34;                      # required
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        MatchIsTouchpad &amp;#34;yes&amp;#34;                           # required
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        Driver          &amp;#34;synaptics&amp;#34;                     # required
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        Option          &amp;#34;MinSpeed&amp;#34;              &amp;#34;0.5&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        Option          &amp;#34;MaxSpeed&amp;#34;              &amp;#34;1.0&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        Option          &amp;#34;AccelFactor&amp;#34;           &amp;#34;0.075&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        Option          &amp;#34;TapButton1&amp;#34;            &amp;#34;1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        Option          &amp;#34;TapButton2&amp;#34;            &amp;#34;3&amp;#34;     # multitouch
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        Option          &amp;#34;TapButton3&amp;#34;            &amp;#34;2&amp;#34;     # multitouch
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        Option          &amp;#34;VertTwoFingerScroll&amp;#34;   &amp;#34;1&amp;#34;     # multitouch
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        Option          &amp;#34;HorizTwoFingerScroll&amp;#34;  &amp;#34;1&amp;#34;     # multitouch
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        Option          &amp;#34;VertEdgeScroll&amp;#34;        &amp;#34;1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        Option          &amp;#34;CoastingSpeed&amp;#34;         &amp;#34;8&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        Option          &amp;#34;CornerCoasting&amp;#34;        &amp;#34;1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        Option          &amp;#34;CircularScrolling&amp;#34;     &amp;#34;1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        Option          &amp;#34;CircScrollTrigger&amp;#34;     &amp;#34;7&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        Option          &amp;#34;EdgeMotionUseAlways&amp;#34;   &amp;#34;1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        Option          &amp;#34;LBCornerButton&amp;#34;        &amp;#34;8&amp;#34;     # browser &amp;#34;back&amp;#34; btn
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        Option          &amp;#34;RBCornerButton&amp;#34;        &amp;#34;9&amp;#34;     # browser &amp;#34;forward&amp;#34; btn
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;EndSection
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After saving this file, reboot or run &lt;code&gt;killall Xorg&lt;/code&gt; as root.&lt;/p&gt;
&lt;h3 id=&#34;sleep&#34;&gt;Sleep
&lt;/h3&gt;&lt;p&gt;I haven&amp;rsquo;t investigated this properly, but I would steer clear of suspend-to-RAM, and set your power settings to hibernate (ie suspend-to-disk) instead. This is one error you might get on wake (if you are lucky enough to get a display after it wakes):&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-wake.jpg&#34;
	width=&#34;1024&#34;
	height=&#34;768&#34;
	srcset=&#34;https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-wake_hu_b6ccb602e42c9c38.jpg 480w, https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-wake_hu_6aa52602186b7853.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;This is not a kernel thing, as a no-X install can &lt;code&gt;pm-suspend&lt;/code&gt; without issue.&lt;/p&gt;
&lt;h3 id=&#34;sudo&#34;&gt;Sudo
&lt;/h3&gt;&lt;p&gt;By default, the user you create during the Debian setup is not in the &lt;code&gt;sudo&lt;/code&gt; group. To change this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;su
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;adduser joebloggs sudo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You need to log out then again for this to affect your session.&lt;/p&gt;
&lt;h2 id=&#34;making-xfce-more-usable&#34;&gt;Making XFCE more usable
&lt;/h2&gt;&lt;p&gt;XFCE was my desktop of choice, so at this point, you can either stop reading or run this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install xfce4 xfce4-goodies
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;appearance&#34;&gt;Appearance
&lt;/h3&gt;&lt;p&gt;Because it runs GTK-2 and not GTK-3, GNOME apps will look ugly beside XFCE apps if you don&amp;rsquo;t choose settings which work well for both toolkits. I chose these ones but there are other good combinations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Window Manager -&amp;gt; Theme: Default-4.6&lt;/li&gt;
&lt;li&gt;Appearance -&amp;gt; Style: Anquita&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you use it, then you should open &lt;code&gt;gnome-terminal&lt;/code&gt; now. It defaults to black-on-black under XFCE, which you will want to swap out for something less stupid.&lt;/p&gt;
&lt;h3 id=&#34;replacing-thunar-with-nautilus&#34;&gt;Replacing Thunar with Nautilus
&lt;/h3&gt;&lt;p&gt;Thunar is great, but Nautilus is more familiar to me, and can easily be set up as the preferred file browser:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Preferred Applications -&amp;gt; Utilities -&amp;gt; File Manager: Nautilus&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thunar will hold onto your desktop unless you remove it from Session and Startup (tab over to &amp;lsquo;Session&amp;rsquo; and delete &lt;code&gt;xfdesktop&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;To tell Nautilus to handle the desktop, install &lt;code&gt;gnome-tweak-tool&lt;/code&gt;, and check the box labelled &amp;lsquo;Have file manager handle the desktop&amp;rsquo;. Next time you start Nautilus, it will give you a working desktop.&lt;/p&gt;
&lt;h3 id=&#34;disable-screensavers&#34;&gt;Disable screensavers
&lt;/h3&gt;&lt;p&gt;XFCE has some very cool screensavers, but personally I think this part of desktop computing is a bit last-century:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Settings -&amp;gt; Screensaver: Blank screen only&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The program XScreenSaver itself is a bit of an eyesore. If you don&amp;rsquo;t like it, &lt;a class=&#34;link&#34; href=&#34;http://crunchbang.org/forums/viewtopic.php?pid=69756%23p69756&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this forum post&lt;/a&gt; has some suggestions for alternatives.&lt;/p&gt;
&lt;h3 id=&#34;getting-a-calendar&#34;&gt;Getting a calendar
&lt;/h3&gt;&lt;p&gt;The default clock on the panel is not clickable. Simply remove it and add the &amp;lsquo;DateTime&amp;rsquo; widget. This can show a clock with a drop-down calendar, which is basically standard.&lt;/p&gt;
&lt;h3 id=&#34;getting-print-screen-to-work&#34;&gt;Getting &amp;lsquo;Print Screen&amp;rsquo; to work
&lt;/h3&gt;&lt;p&gt;XFCE makes this super easy to set up (once you turn &lt;a class=&#34;link&#34; href=&#34;http://ubuntuforums.org/showthread.php?t=1716649&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;up this thread&lt;/a&gt; via a search):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Settings manager -&amp;gt; Keyboard -&amp;gt; Application shortcuts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Add a new shortcut to this command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;xfce4-screenshooter -f
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then hit Print, and you should get this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-screenshot.jpg&#34;
	width=&#34;402&#34;
	height=&#34;49&#34;
	srcset=&#34;https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-screenshot_hu_6b07f2211b39c9a5.jpg 480w, https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-screenshot_hu_8c1215de0160eac.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;820&#34;
		data-flex-basis=&#34;1968px&#34;
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;external-monitor&#34;&gt;External monitor
&lt;/h3&gt;&lt;p&gt;When you use an external monitor and switch off the laptop display, you can get stuck without a screen if you pull out the cable! The XFCE screen-switching app (mapped to Fn-F5 on my keyboard) is not really navigable by keyboard, so I added this shortcut as well:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-screen.jpg&#34;
	width=&#34;369&#34;
	height=&#34;26&#34;
	srcset=&#34;https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-screen_hu_bee5cf042a78dc1a.jpg 480w, https://mike42.me/blog/2013-03-debian-xfce-on-toshiba-nb550d/2013-03-01-screen_hu_4fc7dab766e6d351.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;1419&#34;
		data-flex-basis=&#34;3406px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The command &lt;code&gt;xrandr --auto&lt;/code&gt; will switch on any connected monitor with a basic default resolution, fixing your display without rebooting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 2013-03-15:&lt;/strong&gt; I changed this to Shift+Alt+F5, because some programs use the above shortcut, rendering it useless when said programs have focus.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>qtHiero: Open-source Egyptian hieroglyph editor</title>
        <link>https://mike42.me/blog/2013-01-qthiero</link>
        <pubDate>Wed, 30 Jan 2013 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2013-01-qthiero</guid>
        <description>&lt;p&gt;I&amp;rsquo;m just starting out with Qt4 and C++ and came up with &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/qtHiero&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this semi-useful little tool&lt;/a&gt; for marking up Egyptian hieroglyphs in &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/Manuel_de_Codage&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;MdC&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2013-01-qthiero/2013-01-30-qtHiero.png&#34;
	width=&#34;767&#34;
	height=&#34;421&#34;
	srcset=&#34;https://mike42.me/blog/2013-01-qthiero/2013-01-30-qtHiero_hu_7d508e23822e54c.png 480w, https://mike42.me/blog/2013-01-qthiero/2013-01-30-qtHiero_hu_674d0c9be8dd1238.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xl&#34; 
		data-flex-grow=&#34;182&#34;
		data-flex-basis=&#34;437px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;So far the only annoying Qt-quirk I&amp;rsquo;ve found is the lack of support for non-&lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/Plane_%28Unicode%29#Basic_Multilingual_Plane&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;BMP&lt;/a&gt; unicode characters in the QChar type. Turns out you need to use a QString with two QChars, which is exactly the situation which QChar is supposed to solve (by being larger than 8 bits so that there is a 1-1 correspondence between written characters and QChars in a string).&lt;/p&gt;
&lt;p&gt;The unfortunate hack I had to put in for fetching a hieroglyph from a codepoint looked like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * Return a QString from a unicode code-point
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; **/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;QString&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MainWindow&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;::&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;unicode2qstr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uint32_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;character&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0x10000&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;character&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* BMP character. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;QString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;QChar&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;character&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0x10000&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;character&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* Non-BMP character, return surrogate pair */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;code&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;QChar&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;glyph&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;code&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;character&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0x10000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;glyph&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;QChar&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0xD800&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;code&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;glyph&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;QChar&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0xDC00&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;code&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0x3FF&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;QString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;glyph&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* character &amp;gt; 0x10FFF */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;QString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The Qt developer tools get a 10/10 from me though. I say this mainly because &lt;a class=&#34;link&#34; href=&#34;http://glade.gnome.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;glade&lt;/a&gt; runs like a slug at the best of times.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Making an XKCD-style password generator in C&#43;&#43;</title>
        <link>https://mike42.me/blog/2012-11-making-an-xkcd-style-password-generator-in-cpp</link>
        <pubDate>Wed, 28 Nov 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-11-making-an-xkcd-style-password-generator-in-cpp</guid>
        <description>&lt;p&gt;I&amp;rsquo;m learning C++ at the moment, and I don&amp;rsquo;t find long tutorials or studying the standard template library to be particularly fun, as compared with actually building things.&lt;/p&gt;
&lt;p&gt;Making &lt;a class=&#34;link&#34; href=&#34;http://xkcd.com/936/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this type of&lt;/a&gt; password-generator is not new, but it is a nice practical exercise to start out in any language.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2012-11-making-an-xkcd-style-password-generator-in-cpp/2012-11-12-passwordgen.png&#34;
	width=&#34;534&#34;
	height=&#34;518&#34;
	srcset=&#34;https://mike42.me/blog/2012-11-making-an-xkcd-style-password-generator-in-cpp/2012-11-12-passwordgen_hu_f2d72dee0b5f37c3.png 480w, https://mike42.me/blog/2012-11-making-an-xkcd-style-password-generator-in-cpp/2012-11-12-passwordgen_hu_de6b1e30b9838488.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;103&#34;
		data-flex-basis=&#34;247px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;get-a-list-of-common-english-words&#34;&gt;Get a list of common English words
&lt;/h2&gt;&lt;p&gt;Googling &amp;ldquo;common English words&amp;rdquo; yielded &lt;a class=&#34;link&#34; href=&#34;http://www.englishclub.com/vocabulary/common-words-5000.htm&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this list&lt;/a&gt;, purporting to contain 5,000 words. Unfortunately it contains almost 1,000 duplicates and numerous non-words! Wiktionary has a much higher-quality list of words &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/w/index.php?title=Wiktionary:Frequency_lists/PG/2006/04/1-10000&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;compiled from Project Gutenberg&lt;/a&gt;, but the markup looks a bit like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;==== 1 - 1000 ====
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;===== 1 - 100 =====
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[[the]] = 56271872
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[[of]] = 33950064
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[[and]] = 29944184
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[[to]] = 25956096
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[[in]] = 17420636
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[[I]] = 11764797  
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Noting the wikilinks surrounding each word, I put together this PHP script to extract the link destinations and called it &lt;code&gt;get-wikilinks.php&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#!/usr/bin/php
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Return list of wikilinked words from input text */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;explode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;[[&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;file_get_contents&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;php://stdin&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;foreach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$text&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$link&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$rbrace&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;strpos&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$link&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;]]&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$rbrace&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* Also escape on [[foo|bar]] links */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$pipe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;strpos&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$link&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;|&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$pipe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;false&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$pipe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$rbrace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nv&#34;&gt;$rbrace&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$pipe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$word&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;trim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;substr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$link&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$rbrace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;strpos&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$word&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#39;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;false&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;is_numeric&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;substr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$word&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;cm&#34;&gt;/* Leave out words with apostrophes or starting with numbers */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$word&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The output of this script is much more workable:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ chmod +x get-wikilinks.php
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cat wikt.txt | ./get-wikilinks.php
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;the
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;of
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;and
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;to
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;in
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;I
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Using &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/Sort_%28Unix%29&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;sort&lt;/a&gt; and &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/Uniq&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;uniq&lt;/a&gt; makes a top-notch list of common words, ready for an app to digest:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cat wikt.txt | ./get-wikilinks.php | sort | uniq &amp;gt; wordlist.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;write-some-c&#34;&gt;Write some C++
&lt;/h2&gt;&lt;p&gt;There are two problems being solved here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reading a file into memory
&lt;ul&gt;
&lt;li&gt;An &lt;code&gt;ifstream&lt;/code&gt; is used to access the file, and &lt;code&gt;getline()&lt;/code&gt; will return false when EOF has been reached.&lt;/li&gt;
&lt;li&gt;Each line is loaded into a &lt;code&gt;vector&lt;/code&gt; (roughly the same type of container as an &lt;code&gt;ArrayList&lt;/code&gt; in Java), which is resized dynamically and accessed like an array.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Choosing random numbers
&lt;ul&gt;
&lt;li&gt;These are seeded from a &lt;code&gt;random_device&lt;/code&gt;, being more cross-platform than reading from a file like &lt;code&gt;/dev/urandom&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Note that &lt;code&gt;random&lt;/code&gt; is new to C++11.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;pwcpp&#34;&gt;pw.cpp
&lt;/h3&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;fstream&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;random&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;using&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;namespace&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[])&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;wordlist.txt&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Parse command-line arguments */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;max&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;max&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;atoi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Open word list file */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ifstream&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fail&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;cerr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;ERROR: Failed to open &amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fname&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;endl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Read to end and load words */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;vector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wordList&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;while&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;getline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;wordList&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;push_back&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Seed from random device */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;random_device&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;default_random_engine&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;gen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;gen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;seed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uniform_int_distribution&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dist&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wordList&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Output as many passwords as required */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pwLen&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wordId&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;j&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;max&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;j&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;j&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pwLen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;j&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;cout&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wordList&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dist&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;j&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pwLen&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;cout&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;endl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;compile&#34;&gt;Compile
&lt;/h2&gt;&lt;p&gt;Lots of projects in compiled languages have a Makefile, so that you can compile them without having to type out all of the compiler options manually.&lt;/p&gt;
&lt;p&gt;Makefiles are &lt;a class=&#34;link&#34; href=&#34;http://www.gnu.org/software/make/manual/make.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;a useful tool&lt;/a&gt; to learn properly, but for a project this tiny, something simple is fine:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-makefile&#34; data-lang=&#34;makefile&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	g++ pw.cpp -o pw -std&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;c++11
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;clean&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	rm -f pw
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can compile and run the generator:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./pw
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The image at the top of this blog post is from running &lt;code&gt;./pw 30&lt;/code&gt; to generate 30 passwords.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Downtime</title>
        <link>https://mike42.me/blog/2012-11-downtime</link>
        <pubDate>Sat, 10 Nov 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-11-downtime</guid>
        <description>&lt;p&gt;Looks like one of Facebook&amp;rsquo;s webservers took a nap yesterday.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2012-11-downtime/2012-11-10-fb.png&#34;
	width=&#34;585&#34;
	height=&#34;273&#34;
	srcset=&#34;https://mike42.me/blog/2012-11-downtime/2012-11-10-fb_hu_a83306f469db6205.png 480w, https://mike42.me/blog/2012-11-downtime/2012-11-10-fb_hu_29fec7f9dd42420c.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;214&#34;
		data-flex-basis=&#34;514px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;When they designed this error page, I wonder if they realised that both the &amp;lsquo;Help&amp;rsquo; and &amp;lsquo;Go back&amp;rsquo; links give you the same error again.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Pyrocket and Ubuntu</title>
        <link>https://mike42.me/blog/2012-10-pyrocket-and-ubuntu</link>
        <pubDate>Thu, 18 Oct 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-10-pyrocket-and-ubuntu</guid>
        <description>&lt;p&gt;I have a great USB rocket launcher. it&amp;rsquo;s more useful than a computer mouse most of the time. I spotted a moth on the roof the other day, and hadn&amp;rsquo;t installed &lt;a class=&#34;link&#34; href=&#34;http://code.google.com/p/pyrocket/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;pyrocket&lt;/a&gt; on this computer yet.&lt;/p&gt;
&lt;p&gt;A quick &lt;code&gt;apt-get install pyrocket&lt;/code&gt; is all it takes to solve that though, right? No such luck.&lt;/p&gt;
&lt;p&gt;This package has been &lt;a class=&#34;link&#34; href=&#34;https://bugs.launchpad.net/ubuntu/&amp;#43;source/pyrocket/&amp;#43;bug/1055778&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;broken for several months now&lt;/a&gt; in the Ubuntu repos, though the dependency issue is fixed in a fork of the upstream.&lt;/p&gt;
&lt;p&gt;So this is the error you get at the moment:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Traceback (most recent call last):
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  File &amp;#34;/usr/bin/pyrocket&amp;#34;, line 17, in &amp;lt;module&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    from rocket_frontend import RocketWindow
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  File &amp;#34;/usr/lib/pymodules/python2.7/rocket_frontend.py&amp;#34;, line 11, in &amp;amp;lt;module&amp;amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    from rocket_webcam import VideoWindow
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  File &amp;#34;/usr/lib/pymodules/python2.7/rocket_webcam.py&amp;#34;, line 2, in &amp;amp;lt;module&amp;amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    from opencv import cv, highgui
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ImportError: No module named opencv
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The solution, beyond complaining on the bug tracker, is to read the bug report &lt;a class=&#34;link&#34; href=&#34;http://code.google.com/p/pyrocket/issues/detail?id=17&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;here&lt;/a&gt; and do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone https://github.com/stadler/pyrocket
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cd pyrocket/src
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./pyrocket.py
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But the moth had escaped by then.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Chromium B.S.U.</title>
        <link>https://mike42.me/blog/2012-10-chromium-b-s-u</link>
        <pubDate>Fri, 05 Oct 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-10-chromium-b-s-u</guid>
        <description>&lt;p&gt;I was looking to install the &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/Chromium_%28web_browser%29&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Chromium&lt;/a&gt; web browser and installed the &lt;code&gt;chromium-bsu&lt;/code&gt; package at the suggestion of the package manager:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mike@mikebox:~$ sudo apt-get install chromium
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Package chromium is not available, but is referred to by another package.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;However the following packages replace it:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  chromium-bsu
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;All the most important discoveries were &lt;a class=&#34;link&#34; href=&#34;http://science.discovery.com/brink/top-ten/accidental-inventions/inventions.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;made by accident&lt;/a&gt;: penicillin, teflon, coke, and what turned out to be a &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/Chromium_B.S.U.&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;very fun space-shooter game&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2012-10-chromium-b-s-u/2012-10-05-chromium-bsu.png&#34;
	width=&#34;280&#34;
	height=&#34;232&#34;
	srcset=&#34;https://mike42.me/blog/2012-10-chromium-b-s-u/2012-10-05-chromium-bsu_hu_3012de0950727f38.png 480w, https://mike42.me/blog/2012-10-chromium-b-s-u/2012-10-05-chromium-bsu_hu_aff6d64d3586bc52.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Chromium B.S.U. screenshot&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;120&#34;
		data-flex-basis=&#34;289px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;About an hour of clicking later - back to work. Installing the wrong package is a real time sink!&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Changing the IP address on a Cisco switch</title>
        <link>https://mike42.me/blog/2012-10-changing-the-ip-address-on-a-cisco-switch</link>
        <pubDate>Wed, 03 Oct 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-10-changing-the-ip-address-on-a-cisco-switch</guid>
        <description>&lt;p&gt;Cisco switches are a bit cryptic, but well documented. You can generally do just about anything with enough patience and Googling, but even simple configuration tasks can be difficult if you&amp;rsquo;re not familiar with the interface.&lt;/p&gt;
&lt;h2 id=&#34;basic-tips&#34;&gt;Basic tips
&lt;/h2&gt;&lt;p&gt;These are my 3 tips to configuring Cisco devices:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;telnet
&lt;ul&gt;
&lt;li&gt;Always telnet or SSH to the switch to log on. Don&amp;rsquo;t use configuration utilities or a web interface, because everything that turns up on Google refers to the command-line interface.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;enable
&lt;ul&gt;
&lt;li&gt;All of the useful options are hidden by default. Use &lt;code&gt;enable&lt;/code&gt; to do serious work.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;?
&lt;ul&gt;
&lt;li&gt;Pressing &lt;code&gt;?&lt;/code&gt; pops up a list of ways you can complete the current command.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;for-example-ip-settings&#34;&gt;For example: IP settings
&lt;/h2&gt;&lt;p&gt;The first step when moving around a used switch is to set it up for a different network. Here is where you will find the IP config:&lt;/p&gt;
&lt;p&gt;Log in:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;telnet 10.1.x.x
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now enable the admin options:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;example-switch&amp;gt;enable
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Password: (type in your password)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that the prompt has changed from &lt;code&gt;&amp;gt;&lt;/code&gt; to &lt;code&gt;#&lt;/code&gt;. We can now change the IP and subnet mask of the switch:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;example-switch#
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;interface vlan 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ip address 10.1.x.x 255.255.x.x
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>Wikitext parser development</title>
        <link>https://mike42.me/blog/2012-09-wikitext-parser-development</link>
        <pubDate>Fri, 21 Sep 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-09-wikitext-parser-development</guid>
        <description>&lt;p&gt;I&amp;rsquo;ve just uploaded the first development version (0.4.2) of my &lt;a class=&#34;link&#34; href=&#34;https://github.com/mike42/wikitext&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;in-house wikitext parser&lt;/a&gt;. This example shows off what it can do:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2012-09-wikitext-parser-development/2012-09-22-wikitext.png&#34;
	width=&#34;675&#34;
	height=&#34;752&#34;
	srcset=&#34;https://mike42.me/blog/2012-09-wikitext-parser-development/2012-09-22-wikitext_hu_72640a039014075c.png 480w, https://mike42.me/blog/2012-09-wikitext-parser-development/2012-09-22-wikitext_hu_165d2f0c94a0ef2e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;89&#34;
		data-flex-basis=&#34;215px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve made this with the intention of never requiring users to input HTML in an application which I&amp;rsquo;m working on. So far, so good.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Weird bug in iPad mail app</title>
        <link>https://mike42.me/blog/2012-09-weird-bug-in-ipad-mail-app</link>
        <pubDate>Sat, 08 Sep 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-09-weird-bug-in-ipad-mail-app</guid>
        <description>&lt;p&gt;If you use the iPad mail app with Gmail, set up as an exchange account, you get a folder labelled &lt;strong&gt;[Gmail]&lt;/strong&gt; which has your spam and starred mail folders.&lt;/p&gt;
&lt;h2 id=&#34;the-bug&#34;&gt;The bug
&lt;/h2&gt;&lt;p&gt;It turns out that an undocumented feature turns up if you also create a label called &lt;strong&gt;[Gmail]&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2012-09-weird-bug-in-ipad-mail-app/2012-09-07-labelsetup-mistake.png&#34;
	width=&#34;247&#34;
	height=&#34;88&#34;
	srcset=&#34;https://mike42.me/blog/2012-09-weird-bug-in-ipad-mail-app/2012-09-07-labelsetup-mistake_hu_e20d7a67192e5bb0.png 480w, https://mike42.me/blog/2012-09-weird-bug-in-ipad-mail-app/2012-09-07-labelsetup-mistake_hu_cde12b481cd7f16e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;280&#34;
		data-flex-basis=&#34;673px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2012-09-weird-bug-in-ipad-mail-app/2012-09-07-labels-bad.png&#34;
	width=&#34;325&#34;
	height=&#34;356&#34;
	srcset=&#34;https://mike42.me/blog/2012-09-weird-bug-in-ipad-mail-app/2012-09-07-labels-bad_hu_c2aa10c3b2ebfbc6.png 480w, https://mike42.me/blog/2012-09-weird-bug-in-ipad-mail-app/2012-09-07-labels-bad_hu_a8ed33ce35ffdef.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;91&#34;
		data-flex-basis=&#34;219px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Labels and these special folders are different, so why are they getting mixed up? Or if they&amp;rsquo;re meant to be mixed, then why are their two &lt;strong&gt;[Gmail]&lt;/strong&gt; headings?&lt;/p&gt;
&lt;p&gt;It seems to have slipped through the developers&amp;rsquo; minds when they stored them in the same place, because the app behaves very inconsistently with this setup (variously duplicating labels and headings, and then leaving one list out of sync when changes are made).&lt;/p&gt;
&lt;h2 id=&#34;workaround-rename-your-labels&#34;&gt;Workaround: Rename your labels
&lt;/h2&gt;&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2012-09-weird-bug-in-ipad-mail-app/2012-09-07-labelsetup-good.png&#34;
	width=&#34;148&#34;
	height=&#34;94&#34;
	srcset=&#34;https://mike42.me/blog/2012-09-weird-bug-in-ipad-mail-app/2012-09-07-labelsetup-good_hu_5c29352d0d3cfb82.png 480w, https://mike42.me/blog/2012-09-weird-bug-in-ipad-mail-app/2012-09-07-labelsetup-good_hu_a636aca3e8d39968.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;157&#34;
		data-flex-basis=&#34;377px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2012-09-weird-bug-in-ipad-mail-app/2012-09-07-labels-good.png&#34;
	width=&#34;327&#34;
	height=&#34;272&#34;
	srcset=&#34;https://mike42.me/blog/2012-09-weird-bug-in-ipad-mail-app/2012-09-07-labels-good_hu_86a0d3ea9517c3e7.png 480w, https://mike42.me/blog/2012-09-weird-bug-in-ipad-mail-app/2012-09-07-labels-good_hu_8437f11653991b34.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;120&#34;
		data-flex-basis=&#34;288px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I hope the developers are paying more attention next release-. I&amp;rsquo;m only blogging this because I couldn&amp;rsquo;t turn up much information on this from a web search.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Re-arranging  columns on JTables</title>
        <link>https://mike42.me/blog/2012-09-re-arranging-columns-on-jtables</link>
        <pubDate>Wed, 05 Sep 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-09-re-arranging-columns-on-jtables</guid>
        <description>&lt;p&gt;I&amp;rsquo;m only new to Java UI work, and was surprised to see how easy it is to work with tables.&lt;/p&gt;
&lt;p&gt;In my case I&amp;rsquo;m trying to build an application where the user need to be able to sort columns manually.&lt;/p&gt;
&lt;p&gt;A few things I&amp;rsquo;ve learnt:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JTables only show column headers if the table is placed inside a JScrollPane&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s really annoying to drag-and-drop narrow, resizable columns, so turn off resizing.
I ended up with this user-rearrangeable table:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2012-09-re-arranging-columns-on-jtables/2012-09-05-tables.png&#34;
	width=&#34;543&#34;
	height=&#34;108&#34;
	srcset=&#34;https://mike42.me/blog/2012-09-re-arranging-columns-on-jtables/2012-09-05-tables_hu_86ec16679ee7825c.png 480w, https://mike42.me/blog/2012-09-re-arranging-columns-on-jtables/2012-09-05-tables_hu_3fb9c3bb7dcc62f5.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;502&#34;
		data-flex-basis=&#34;1206px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Basic code for this, thanks to &lt;a class=&#34;link&#34; href=&#34;https://developers.google.com/java-dev-tools/download-wbpro&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Google Windowbuilder&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;java.awt.EventQueue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;javax.swing.JFrame&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;javax.swing.JTable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;javax.swing.table.DefaultTableModel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;javax.swing.JScrollPane&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;TableTestWindow&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;private&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;JFrame&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;frame&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;private&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;JTable&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;table&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * Launch the application.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     */&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;static&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EventQueue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;invokeLater&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Runnable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;try&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TableTestWindow&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;window&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TableTestWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;window&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;frame&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;setVisible&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;catch&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Exception&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;printStackTrace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * Create the application.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     */&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;TableTestWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;initialize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * Initialize the contents of the frame.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     */&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;private&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;initialize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;frame&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;JFrame&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;frame&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;setBounds&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;525&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;520&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;frame&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;setDefaultCloseOperation&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;JFrame&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;EXIT_ON_CLOSE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;frame&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;getContentPane&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;setLayout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;JScrollPane&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;scrollPane&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;JScrollPane&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;scrollPane&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;setBounds&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;460&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;440&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;frame&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;getContentPane&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;scrollPane&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;table&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;JTable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;table&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;setFillsViewportHeight&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;scrollPane&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;setViewportView&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;table&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;table&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;setRowSelectionAllowed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;table&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;setColumnSelectionAllowed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;table&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;setModel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;DefaultTableModel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Object&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[][]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;A&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;D&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;E&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;F&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;G&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;H&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;I&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;J&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;K&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;L&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;M&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;N&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;O&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;P&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Q&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;R&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;S&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;T&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;U&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;V&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;W&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;X&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Y&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Z&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;             * Java coughs up warnings if we dont do this
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;             */&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;private&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;static&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;final&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;serialVersionUID&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;1L&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Class&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;getColumnClass&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;columnIndex&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;boolean&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;isCellEditable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;row&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;column&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;26&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;table&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;getColumnModel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;getColumn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;setResizable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;table&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;getColumnModel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;getColumn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;setPreferredWidth&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>Web hosting move complete</title>
        <link>https://mike42.me/blog/2012-07-web-hosting-move-complete</link>
        <pubDate>Tue, 31 Jul 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-07-web-hosting-move-complete</guid>
        <description>&lt;p&gt;Over the past week we&amp;rsquo;ve moved all of our hosting to the bigger, better, faster servers at DreamHost.&lt;/p&gt;
&lt;p&gt;So far, so good!&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Australian telephone tones</title>
        <link>https://mike42.me/blog/2012-06-australian-telephone-tones</link>
        <pubDate>Wed, 06 Jun 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-06-australian-telephone-tones</guid>
        <description>&lt;p&gt;I made this set of telephone tones for an IP-PBX running asterisk. A lot of telephone-related audio files on the Internet seem to be recordings of actual beeps, so the quality is not great.&lt;/p&gt;
&lt;h2 id=&#34;tones&#34;&gt;Tones
&lt;/h2&gt;&lt;p&gt;Given that they are trivial to synthesise with Audacity, I made these audio files::&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2012-06-australian-telephone-tones/Au-DialB.ogg&#34; &gt;Dial tone&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2012-06-australian-telephone-tones/Au-Busy-15s.ogg&#34; &gt;Busy tone&lt;/a&gt; (or &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2012-06-australian-telephone-tones/Au-BusyLoop.ogg&#34; &gt;single tone to loop&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2012-06-australian-telephone-tones/Au-CallWaiting-15s.ogg&#34; &gt;Call waiting tone&lt;/a&gt; (or &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2012-06-australian-telephone-tones/Au-CallWaiting.ogg&#34; &gt;single tone to loop&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2012-06-australian-telephone-tones/Au-Ringing-15s.ogg&#34; &gt;Ringing tone&lt;/a&gt; (or &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2012-06-australian-telephone-tones/Au-RingingLoop.ogg&#34; &gt;single tone to loop&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;format-conversion&#34;&gt;Format conversion
&lt;/h2&gt;&lt;p&gt;To convert them to &lt;code&gt;.ulaw&lt;/code&gt; format for asterisk (click &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2012-06-australian-telephone-tones/Au-Phone-Tones-ulaw.zip&#34; &gt;here&lt;/a&gt; to download archive), I saved them as a &lt;code&gt;.wav&lt;/code&gt; file and ran this bash script over the directory:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; a in *.wav&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	sox &lt;span class=&#34;nv&#34;&gt;$a&lt;/span&gt; -r &lt;span class=&#34;m&#34;&gt;8000&lt;/span&gt; -t ul &lt;span class=&#34;nv&#34;&gt;$a&lt;/span&gt;.ulaw
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;making-tones-for-other-countries&#34;&gt;Making tones for other countries
&lt;/h2&gt;&lt;p&gt;Get a copy of the document &amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://www.itu.int/pub/T-SP-E.180-2010&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Various tones used in national networks (According to ITU-T Recommendation E.180) (03/1998)&lt;/a&gt;&amp;rdquo;. It describes the tones used in most of the world. There is also a Cisco tones database, which has slightly different numbers.&lt;/p&gt;
&lt;p&gt;Open up Audacity and use the &lt;strong&gt;Generate → Tones&lt;/strong&gt; feature to make the first beep. Where there are multiple frequencies, make each frequency in different tracks, then merge them into a single track.&lt;/p&gt;
&lt;p&gt;Use &lt;strong&gt;Generate → Silence&lt;/strong&gt; to add the delay on the end, then continue from there&lt;/p&gt;
&lt;p&gt;Afterward, you need to normalise the volume. Read the number from the volume Cisco tones database, then use &lt;strong&gt;Effect → Amplify&lt;/strong&gt;, and set the new peak volume to the value shown. For the above tones this is -10 or -13dB.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>HP Mini 210 review</title>
        <link>https://mike42.me/blog/2012-05-hp-mini-210-review</link>
        <pubDate>Fri, 25 May 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-05-hp-mini-210-review</guid>
        <description>&lt;p&gt;I used a HP Mini 210 netbook for around 18 months. It cost $329 AUD when I bought it, and had Windows XP and a 160GB hard drive.&lt;/p&gt;
&lt;p&gt;I was originally interested in dual-booting Windows alongside Linux, but HP support wouldn&amp;rsquo;t provide recovery disks or the Windows licence key, so I ran it with only Linux instead.&lt;/p&gt;
&lt;p&gt;Here are some features to note:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An SD card can be placed in the slot and stays out of the way.&lt;/li&gt;
&lt;li&gt;The VGA port makes it suitable for doing presentations.&lt;/li&gt;
&lt;li&gt;The battery life is not fantastic. Around 3 hours when new, and reduced to just 20 minutes or so by the first year.&lt;/li&gt;
&lt;li&gt;Not particularly durable. The right-click stopped working on the mousepad after a while. I enabled mac-style gestures in Ubuntu to overcome this.&lt;/li&gt;
&lt;li&gt;The ventilation is poor. It has no vents on the bottom at all, which is great for keeping the inside dry, but it has a very weak fan and did not handle heavy loads gracefully.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some things you can do to improve it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;As soon as I found out how to open the case (&lt;a class=&#34;link&#34; href=&#34;http://www.youtube.com/watch?v=ISIBCLS9MuM&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;video&lt;/a&gt;), I got an &lt;a class=&#34;link&#34; href=&#34;http://www.intel.com/content/www/us/en/solid-state-drives/solid-state-drives-ssd.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Intel SSD&lt;/a&gt;, which was quite expensive, but can be carried over to a future netbook. It makes it quieter, faster, more power efficient, and removes the shock-sensitivity that plagues notebook hard-drives.&lt;/li&gt;
&lt;li&gt;Consider getting a high-capacity battery. I replaced the dead standard size one with a cheap 3rd-party battery (&lt;a class=&#34;link&#34; href=&#34;http://www.battery-shop.com.au/batteries.php/Mini_210&amp;#43;battery&amp;#43;COMPAQ&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;link&lt;/a&gt;), but it could still do with more power.&lt;/li&gt;
&lt;li&gt;The default install is filled with crapware. Either reinstall windows or run something else. GNU/Linux compatibility is great, and it also runs Windows 7 with no problems. It also turns out your Windows XP key is &lt;em&gt;inside&lt;/em&gt; the case, so open it up and use it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It was a good laptop for the price, but not exceptionally fast or durable, particularly and the battery degraded much faster than I would have liked. This netbook should be purchased with the understanding that it will have a short life.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Alphanumeric phone numbers</title>
        <link>https://mike42.me/blog/2012-05-alphanumeric-phone-numbers</link>
        <pubDate>Thu, 17 May 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-05-alphanumeric-phone-numbers</guid>
        <description>&lt;p&gt;Some popular phone numbers are advertised in an alphanumeric form (eg. &lt;code&gt;1300-FOOBAR&lt;/code&gt;), based on the idea that a traditional phone keypad has letters under each number.&lt;/p&gt;
&lt;p&gt;If you are running a VOIP server then you may be interested in this snippet of PHP code to convert them into actual numbers, allowing users to dial by typing that more familiar form.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;normaliseTelephoneNumber&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Return an extension with numbers substituted in place of letters for dialling */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$map&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;A&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;B&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;s2&#34;&gt;&amp;#34;D&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;3&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;E&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;3&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;F&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;3&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;s2&#34;&gt;&amp;#34;G&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;4&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;H&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;4&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;I&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;4&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;s2&#34;&gt;&amp;#34;J&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;5&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;J&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;5&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;L&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;5&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;s2&#34;&gt;&amp;#34;M&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;6&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;N&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;6&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;O&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;6&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;s2&#34;&gt;&amp;#34;P&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;7&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Q&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;7&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;R&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;7&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;S&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;7&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;s2&#34;&gt;&amp;#34;T&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;8&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;U&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;8&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;V&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;8&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;s2&#34;&gt;&amp;#34;W&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;9&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;X&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;9&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Y&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;9&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Z&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;9&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;s2&#34;&gt;&amp;#34;+&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;+&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;#&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;#&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$new&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$hasnumber&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$ext&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;strtoupper&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;strlen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$ext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;substr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$ext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;isset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nv&#34;&gt;$new&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$hasnumber&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;cm&#34;&gt;/* No numbers before letters */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;is_numeric&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nv&#34;&gt;$new&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nv&#34;&gt;$hasnumber&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$hasnumber&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$new&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;cm&#34;&gt;/* Return numeric version as appropriate */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;cm&#34;&gt;/* Leaves full words like &amp;#34;joe&amp;#34; or &amp;#34;bazza&amp;#34; unchanged */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$new&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that this will only alter the number if it &lt;em&gt;begins&lt;/em&gt; with numbers. This is to make sure that the local network extensions (which in my case are ASCII usernames) don&amp;rsquo;t get transformed along the way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;echo normaliseTelephoneNumber(&amp;#34;1300-FOOBAR&amp;#34;).&amp;#34;n&amp;#34;; /* 1300366227 */
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;echo normaliseTelephoneNumber(&amp;#34;mike&amp;#34;).&amp;#34;n&amp;#34;; /* mike */
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>Introducing BigInteger</title>
        <link>https://mike42.me/blog/2012-04-introducing-biginteger</link>
        <pubDate>Sun, 08 Apr 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-04-introducing-biginteger</guid>
        <description>&lt;p&gt;Most ordinary-scale programs don&amp;rsquo;t use very large numbers, but today I&amp;rsquo;ll show you how to use Java to do some more serious calculating, with the &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/Fibonacci_number&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Fibonacci numbers&lt;/a&gt; as an example:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, &amp;hellip;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;The numbers in this sequence always get larger, so you don&amp;rsquo;t need to be a software engineer to see that &lt;code&gt;int&lt;/code&gt; and &lt;code&gt;long&lt;/code&gt; won&amp;rsquo;t be big enough. Just to highlight the problem, here is a naive approach to listing the Fibonacci numbers:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;FibonacciLong&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;static&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;solutions&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;static&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tmp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;solution&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;solution&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;while&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tmp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;solution&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tmp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tmp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;static&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;solution&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;number&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;solutions&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;System&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;out&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;solutions&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;t&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;number&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The output of this program &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/Integer_overflow&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;overflows&lt;/a&gt; after the 93&lt;sup&gt;rd&lt;/sup&gt; term. Java only uses &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/Two%27s_complement&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;signed&lt;/a&gt; integer types, so we end up with a negative number:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;1    0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2    1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;3    1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;4    2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;5    3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;6    5
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;....
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;92    4660046610375530309
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;93    7540113804746346429
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;94    -6246583658587674878
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To find larger values, we can use the &lt;a class=&#34;link&#34; href=&#34;http://docs.oracle.com/javase/1.5.0/docs/api/java/math/BigInteger.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;BigInteger&lt;/a&gt; class, under &lt;code&gt;java.math&lt;/code&gt;. They are constructed like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;BigInteger&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;BigInteger&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;They don&amp;rsquo;t really work like the primitive types. They are manipulated with methods like &lt;code&gt;.add()&lt;/code&gt; and &lt;code&gt;.subtract()&lt;/code&gt;, rather than the operators that we are accustomed to: &lt;code&gt;+ - * / %&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The below code has been written with BigInteger instead of long. It will return the n&lt;sup&gt;th&lt;/sup&gt; term of the Fibonacci sequence, or enumerate solutions until the cows come home.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;java.math.BigInteger&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;FibonacciBigInteger&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;static&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;solutions&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;static&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;static&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Long&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;parseLong&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;BigInteger&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;BigInteger&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;BigInteger&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;BigInteger&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;BigInteger&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tmp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;solution&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;solution&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;while&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tmp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;solution&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tmp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tmp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;static&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;solution&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;BigInteger&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;number&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;solutions&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;||&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;solutions&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;System&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;out&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;number&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;toString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;());&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;System&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The good news is that this program is now capable of working with numbers &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2012-01-converting-numbers-to-words-in-php&#34; &gt;too large to say aloud&lt;/a&gt;. So today is a good day to start using Unix&amp;rsquo;s &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/Wc_%28Unix%29&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;wc&lt;/a&gt; program to appreciate how big these numbers actually are:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mike~$ java FibonacciBigInteger 420000 | wc -m
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;87776
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Subtract one character because there is an end-of-line in the output, and this means that the 420,000&lt;sup&gt;th&lt;/sup&gt; Fibonacci number is 8775 digits long. We have discovered a new fact!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; There is still one variable in the program above that will overflow eventually, so you should also convert that to a BigInteger if you are hoping to calculate past about the nine quintillionth Fibonacci number (which you would be crazy to do with this method).&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Version 0.5 of raycaster released</title>
        <link>https://mike42.me/blog/2012-04-version-0-5-of-raycaster-released</link>
        <pubDate>Thu, 05 Apr 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-04-version-0-5-of-raycaster-released</guid>
        <description>&lt;p&gt;I have finished porting my &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/raycaster/&#34; &gt;raycaster project&lt;/a&gt; to java, fixing it up a bit in the process.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2012-04-version-0-5-of-raycaster-released/mike-raycaster-05.png&#34;
	width=&#34;444&#34;
	height=&#34;450&#34;
	srcset=&#34;https://mike42.me/blog/2012-04-version-0-5-of-raycaster-released/mike-raycaster-05_hu_5d1becaf4489bdb7.png 480w, https://mike42.me/blog/2012-04-version-0-5-of-raycaster-released/mike-raycaster-05_hu_6142c14b9af5b49e.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Mike’s Raycaster at work&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;98&#34;
		data-flex-basis=&#34;236px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Based on this screenshot, I kicked up the brightness a bit too far (feel free to download the source code and fix that!)&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Palindromes</title>
        <link>https://mike42.me/blog/2012-03-palindromes</link>
        <pubDate>Tue, 27 Mar 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-03-palindromes</guid>
        <description>&lt;p&gt;This is a highly miscellaneous Java snippet to find palindromes.&lt;/p&gt;
&lt;p&gt;It will read &lt;code&gt;stdin&lt;/code&gt; line-by-line and spit back the palindromes it finds.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;java.io.*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Palindrome&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/* Return palindromes from a given list of words read from stdin */&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;static&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;boolean&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;okay&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;BufferedReader&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;BufferedReader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;InputStreamReader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;System&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;in&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;try&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/* Read a line, and spit it back again it if is a palindrome */&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;line&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;readLine&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;isPalindrome&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;System&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;out&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;okay&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;catch&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Exception&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/* Exception will be raised after end-of-file */&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;okay&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;while&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;okay&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;static&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;boolean&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;isPalindrome&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/* Return true if a string is palindromic, false otherwise */&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/* Disallow null / single-char palindromes */&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/* Compare first and last, second and second-last, etc) */&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;charAt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;charAt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/* Found different letters, stopping. */&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On a UNIX-like system, you could feed it a dictionary to list all of the palindromes like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;java Palindrome &amp;lt; /etc/dictionaries-common/words
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On my computer that returns 57 palindromes made from ordinary words:&lt;/p&gt;
&lt;p&gt;In alphabetical order, those are: &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/aha&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;aha&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/bib&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;bib&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/bob&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;bob&lt;/a&gt;
&lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/boob&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;boob&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/civic&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;civic&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/dad&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;dad&lt;/a&gt;
&lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/deed&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;deed&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/deified&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;deified&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/did&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;did&lt;/a&gt;
&lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/dud&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;dud&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/eke&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;eke&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/ere&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;ere&lt;/a&gt;
&lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/eve&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;eve&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/ewe&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;ewe&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/eye&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;eye&lt;/a&gt;
&lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/gag&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;gag&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/gig&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;gig&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/hah&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;hah&lt;/a&gt;
&lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/huh&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;huh&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/kayak&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;kayak&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/kook&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;kook&lt;/a&gt;
&lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/level&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;level&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/ma%27am&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;ma&amp;rsquo;am&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/madam&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;madam&lt;/a&gt;
&lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/MGM&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;MGM&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/minim&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;minim&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/mom&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mom&lt;/a&gt;
&lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/mum&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;mum&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/non&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;non&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/noon&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;noon&lt;/a&gt;
&lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/nun&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;nun&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/oho&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;oho&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/pap&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;pap&lt;/a&gt;
&lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/peep&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;peep&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/pep&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;pep&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/pip&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;pip&lt;/a&gt;
&lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/poop&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;poop&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/pop&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;pop&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/pup&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;pup&lt;/a&gt;
&lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/radar&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;radar&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/redder&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;redder&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/refer&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;refer&lt;/a&gt;
&lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/rotor&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;rotor&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/sagas&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;sagas&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/sees&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;sees&lt;/a&gt;
&lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/seres&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;seres&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/sexes&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;sexes&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/shahs&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;shahs&lt;/a&gt;
&lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/sis&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;sis&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/solos&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;solos&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/stats&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;stats&lt;/a&gt;
&lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/tat&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;tat&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/tenet&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;tenet&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/tit&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;tit&lt;/a&gt;
&lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/toot&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;toot&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/tot&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;tot&lt;/a&gt;    &lt;a class=&#34;link&#34; href=&#34;http://en.wiktionary.org/wiki/wow&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;wow&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There are certainly more if we allow 1-letter words or case-insensitive matching (allowing &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/List_of_palindromic_places&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;all sorts of&lt;/a&gt; proper nouns), but I really don&amp;rsquo;t think they count.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Finding prime numbers</title>
        <link>https://mike42.me/blog/2012-03-finding-prime-numbers</link>
        <pubDate>Sat, 17 Mar 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-03-finding-prime-numbers</guid>
        <description>&lt;p&gt;It&amp;rsquo;s not so hard to calculate small-ish primes.&lt;/p&gt;
&lt;p&gt;The below method is called a &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;prime sieve&lt;/a&gt;, and can be calculated manually:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Take two, the smallest prime number.&lt;/p&gt;
&lt;p&gt;We know that no multiples of two are prime (4, 6, 8, 10, 12, etc.), so we can cross them off our list and just print two.&lt;/p&gt;
&lt;p&gt;Then we go to 3. 3 is prime. But 6, 9, 12 and 15 can&amp;rsquo;t be, so we print 3 and cross those multiples off.&lt;/p&gt;
&lt;p&gt;4 has been marked as not prime, so we skip it.&lt;/p&gt;
&lt;p&gt;5 is prime, so we cross off 10, 15, 20.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;and so on and so forth&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Computers are much better at this than humans though, so I wrote this algorithm up in java. You can find all primes up to &lt;em&gt;n&lt;/em&gt; fairly quickly (for small values of &lt;em&gt;n&lt;/em&gt;).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Primes&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;static&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;searchMax&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;16777216&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/* Allow over-riding the maximum */&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;searchMax&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Integer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;parseInt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;boolean&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;isprime&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;boolean&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;searchMax&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tmp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/* Initialise */&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;isprime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;isprime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;searchMax&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;isprime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/* Main loop */&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;searchMax&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;isprime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;System&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;out&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tmp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;while&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tmp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;searchMax&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;isprime&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tmp&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tmp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;System&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Found &amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34; primes between 1 and &amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;searchMax&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34; non-inclusive&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Of course, the limitation of this is that Java isn&amp;rsquo;t terribly good at handling larger arrays, so I wouldn&amp;rsquo;t expect more than a few million primes from this code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; The above code was tested for finding the first 7 million prime numbers.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Getting lost with depth-first search</title>
        <link>https://mike42.me/blog/2012-03-getting-lost-with-depth-first-search</link>
        <pubDate>Wed, 07 Mar 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-03-getting-lost-with-depth-first-search</guid>
        <description>&lt;p&gt;I was thinking about &lt;a href=&#34;http://en.wikipedia.org/wiki/Maze_generation_algorithm&#34;&gt;how to make mazes&lt;/a&gt;, and ended up making a maze generator.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s based on &amp;lsquo;depth-first search&amp;rsquo;, a recursive algorithm to make a spanning tree. Example output below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2012-03-getting-lost-with-depth-first-search/2012-03-maze.png&#34;
	width=&#34;732&#34;
	height=&#34;382&#34;
	srcset=&#34;https://mike42.me/blog/2012-03-getting-lost-with-depth-first-search/2012-03-maze_hu_ca95c5ee44b76329.png 480w, https://mike42.me/blog/2012-03-getting-lost-with-depth-first-search/2012-03-maze_hu_1c4af430d1b580cd.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Example maze output&#34;
	
	
	
		class=&#34;gallery-image img-md&#34; 
		data-flex-grow=&#34;191&#34;
		data-flex-basis=&#34;459px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Java doesn&amp;rsquo;t particularly like deep recursion, so this generator will fizzle out with an error on really big mazes.&lt;/p&gt;
&lt;p&gt;On the other hand, it can produce output as HTML:&lt;/p&gt;


&lt;style&gt;
.maze-83 td { height: 1.5rem; width: 1.5rem; border: none; }
.maze-83 tr { background-color: transparent !important; }
.maze-83 {padding: 1rem;}
.maze-83 table {border-collapse: collapse; margin-left: auto; margin-right: auto; margin-bottom: 0; width: auto;}
&lt;/style&gt;
&lt;div class=&#34;maze-83&#34;&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;td style=&#34;border-top: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-top: 2px solid #000; border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-top: 2px solid #000; border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-top: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-top: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-top: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-top: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-top: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-top: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-top: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td style=&#34;border-left: 2px solid #000; border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td style=&#34;border-left: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td style=&#34;border-left: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;

		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td style=&#34;border-left: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;

		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td style=&#34;border-left: 2px solid #000; border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;

		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td style=&#34;border-left: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;

		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td style=&#34;border-left: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td style=&#34;border-left: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td&gt;&lt;/td&gt;
		&lt;td&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td style=&#34;border-left: 2px solid #000; border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000; border-right: 2px solid #000;&#34;&gt;&lt;/td&gt;

		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
		&lt;td style=&#34;border-bottom: 2px solid #000;&#34;&gt;&lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;


&lt;p&gt;You can download the maze generator here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2012-03-getting-lost-with-depth-first-search/MazeGenerator.jar&#34; &gt;MazeGenerator.jar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2012-03-getting-lost-with-depth-first-search/MazeGenerator-src.tar.gz&#34; &gt;MazeGenerator-src.tar.gz&lt;/a&gt; (source code)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;rsquo;s a command line program. From the terminal, the usage is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;java -jar MazeGenerator.jar [width] [height] [formatting]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Width/height will change the size of your maze. You can set the format to &amp;lsquo;html&amp;rsquo;, or type in a character for the filled-in blocks to be. (The default is u2588 &amp;lsquo;Solid block&amp;rsquo;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update August 2025:&lt;/strong&gt; I&amp;rsquo;ve manually adjusted the HTML markup of the maze to appear correctly on this blog, and it no longer exactly matches the output of this program.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Solving the eight queens puzzle</title>
        <link>https://mike42.me/blog/2012-02-solving-the-eight-queens-puzzle</link>
        <pubDate>Wed, 29 Feb 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-02-solving-the-eight-queens-puzzle</guid>
        <description>&lt;p&gt;In the &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/Eight_queens_puzzle&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;eight queens puzzle&lt;/a&gt;, you need to place eight queens on a chessboard so that they aren&amp;rsquo;t attacking each-other. It has 92 solutions.&lt;/p&gt;
&lt;p&gt;I implemented one method for solving the problem. It works for any &lt;em&gt;n&lt;/em&gt; x &lt;em&gt;n&lt;/em&gt; chessboard, but it&amp;rsquo;s not so fast with large boards.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Compiled: &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2012-02-solving-the-eight-queens-puzzle/Queens.jar&#34; &gt;Queens.jar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Source: &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2012-02-solving-the-eight-queens-puzzle/Queens.java&#34; &gt;Queens.java&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can invoke this with &lt;code&gt;java -jar Queens.jar&lt;/code&gt; for an 8x8 board, or &lt;code&gt;java -jar Queens.jar n&lt;/code&gt; for an &lt;em&gt;n&lt;/em&gt; x &lt;em&gt;n&lt;/em&gt; board with &lt;em&gt;n&lt;/em&gt; queens.&lt;/p&gt;
&lt;p&gt;It works by processing the board in vertical strips, first placing a queen in the top-right, and then attempting to place a queen in the second column at the first available space. Once it crosses the board like this, it has found a solution, but it goes through plenty of bad combinations first.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Beautiful QR Codes</title>
        <link>https://mike42.me/blog/2012-02-beautiful-qr-codes</link>
        <pubDate>Sat, 11 Feb 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-02-beautiful-qr-codes</guid>
        <description>&lt;p&gt;The verdict is in. QR codes are ugly.&lt;/p&gt;
&lt;p&gt;But they don&amp;rsquo;t have to be. Check out the modified code featured on &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/QR_code#Error_correction&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this Wikipedia article&lt;/a&gt;. You don&amp;rsquo;t need to be a QR Code expert to do something like that.&lt;/p&gt;
&lt;p&gt;The basic idea is that QR codes have &lt;em&gt;error correction&lt;/em&gt;. We can generate codes which store the data in multiple places, so that scanners will still read them if they are damaged.&lt;/p&gt;
&lt;h2 id=&#34;scripting-the-whole-operation&#34;&gt;Scripting the whole operation
&lt;/h2&gt;&lt;p&gt;Tedious image editing is not my cup of tea, so I made a PHP class to apply some templates to QR codes and add a centred logo for us.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You will need ImageMagick for PHP to follow these steps, read &lt;a class=&#34;link&#34; href=&#34;http://php.net/manual/en/imagick.setup.php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this page&lt;/a&gt;. On Ubuntu, &lt;code&gt;apt-get install php5-imagick&lt;/code&gt; worked fine for me.&lt;/p&gt;
&lt;p&gt;This is the basic formula: QR Code + Template + Logo = Pretty PR Code&lt;/p&gt;
&lt;p&gt;First we need the QR code. It is best generated with the &lt;a class=&#34;link&#34; href=&#34;http://phpqrcode.sourceforge.net/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;phpqrcode&lt;/a&gt; library. Adding the logo won&amp;rsquo;t work unless we use high error correction (H):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;QRcode::png(&amp;#34;http://bitrevision.com&amp;#34;, &amp;#34;code.png&amp;#34;, &amp;#39;H&amp;#39;, 8, 0);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After that, &lt;code&gt;code.png&lt;/code&gt; looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2012-02-beautiful-qr-codes/2012-02-12-bitrevis-qr-code.png&#34;
	width=&#34;232&#34;
	height=&#34;232&#34;
	srcset=&#34;https://mike42.me/blog/2012-02-beautiful-qr-codes/2012-02-12-bitrevis-qr-code_hu_1d3f328495074f4a.png 480w, https://mike42.me/blog/2012-02-beautiful-qr-codes/2012-02-12-bitrevis-qr-code_hu_9707b71849b5e6da.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;100&#34;
		data-flex-basis=&#34;240px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Now the templates. Note that we used 8x8 pixels per block and 0 for the border above. The resulting code &lt;em&gt;should&lt;/em&gt; line up with one of these templates, adding white lines over the image.&lt;/p&gt;
&lt;p&gt;Save these images to a &amp;rsquo;template&amp;rsquo; folder:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;template-200.png&#34; &gt;template-200.png&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;template-232.png&#34; &gt;template-232.png&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are semi-transparent images which I&amp;rsquo;ve generated to sit over the QR code and allow you to style the pixels.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2012-02-beautiful-qr-codes/template-200.png&#34;
	width=&#34;200&#34;
	height=&#34;200&#34;
	srcset=&#34;https://mike42.me/blog/2012-02-beautiful-qr-codes/template-200_hu_89543a8fd75f2dea.png 480w, https://mike42.me/blog/2012-02-beautiful-qr-codes/template-200_hu_b767ed51c03de722.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;100&#34;
		data-flex-basis=&#34;240px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Next, the logo. We have one of those:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2012-02-beautiful-qr-codes/bitrevis-64x64.png&#34;
	width=&#34;64&#34;
	height=&#34;64&#34;
	srcset=&#34;https://mike42.me/blog/2012-02-beautiful-qr-codes/bitrevis-64x64_hu_19578f8a2ad7d9ea.png 480w, https://mike42.me/blog/2012-02-beautiful-qr-codes/bitrevis-64x64_hu_7fbd5437bbd12785.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;100&#34;
		data-flex-basis=&#34;240px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Time for the code. This class will do most of the work. Just check the template folder contains an template that fits your QR code.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;QR_Pretty&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$template_base&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;template/template-{SIZE}.png&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$qr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;public&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$geometry&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;prettify&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$logo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$output&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* Load image */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;qr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Imagick&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;qr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;readImage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;geometry&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;qr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;getImageGeometry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* Perform modifications */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;add_template&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;add_logo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$logo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* Output image */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$output&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;qr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;setImageFileName&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$output&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;qr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;writeImage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;private&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;add_template&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* This will overlay a template containing white lines,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;            to make the QR codes look less code-ful */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;geometry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;width&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$template_filename&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;{SIZE}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;template_base&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$template&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Imagick&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$template&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;readImage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$template_filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;qr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;compositeImage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$template&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;imagick&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;COMPOSITE_OVER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;private&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;add_logo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$logo_file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* This places a logo in the middle of the QR code,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;            64x64 would be advisable :) */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$logo_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;cm&#34;&gt;/* No logo to add */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$logo&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Imagick&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$logo&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;readImage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$logo_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$logo_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$logo&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;getImageGeometry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;geometry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;width&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$logo_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;width&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;geometry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;height&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$logo_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;height&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;qr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;compositeImage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$logo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;imagick&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;COMPOSITE_OVER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$y&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To use the above class is quite simple. Once you have &lt;code&gt;code.png&lt;/code&gt;, &lt;code&gt;logo.png&lt;/code&gt;, and a folder full of templates, just do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$qr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;QR_Pretty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$qr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;prettify&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;code.png&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;bitrevis.png&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;pretty.png&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That gives us &lt;code&gt;pretty.png&lt;/code&gt;, which looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2012-02-beautiful-qr-codes/2012-02-12-pretty-qr.png&#34;
	width=&#34;232&#34;
	height=&#34;232&#34;
	srcset=&#34;https://mike42.me/blog/2012-02-beautiful-qr-codes/2012-02-12-pretty-qr_hu_efa99b7ad9971c4c.png 480w, https://mike42.me/blog/2012-02-beautiful-qr-codes/2012-02-12-pretty-qr_hu_239552130e449047.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;100&#34;
		data-flex-basis=&#34;240px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Thanks to that error correction, this picture still scans and takes us to &lt;code&gt;http://bitrevision.com&lt;/code&gt;. Note: at the time this blog post was originally published, that is where this blog was hosted.&lt;/p&gt;
&lt;p&gt;Slightly larger logos can be used, but 64x64 is recognisable to a human but still allows the code to scan reliably. Try embedding logos with transparency, too!&lt;/p&gt;
&lt;p&gt;This means there are no more excuses for ugly QR codes. Integrate this into your QR code-producing scripts right away.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>On the price of watermelons</title>
        <link>https://mike42.me/blog/2012-01-on-the-price-of-watermelons</link>
        <pubDate>Tue, 07 Feb 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-01-on-the-price-of-watermelons</guid>
        <description>&lt;p&gt;Watermelons are huge, cheap, and contain a lot of water. The edible part is about 92% water. I wanted to find out whether water from watermelons is cheaper than bottled water at the supermarket.&lt;/p&gt;
&lt;p&gt;I compared prices with other beverages, each is the cheapest in its category. Because prices change all the time, these numbers should be taken with a grain of salt:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Item&lt;/th&gt;
          &lt;th&gt;Price per litre (AUD)&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Home Brand Cordial (diluted 1:4 with free water)&lt;/td&gt;
          &lt;td&gt;0.23&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Water&lt;/td&gt;
          &lt;td&gt;0.46&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Cheap soft drink&lt;/td&gt;
          &lt;td&gt;0.63&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Milk&lt;/td&gt;
          &lt;td&gt;0.89&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Watermelon Juice&lt;/td&gt;
          &lt;td&gt;1.05&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Tropical Juice&lt;/td&gt;
          &lt;td&gt;1.90&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Lipton Iced Tea&lt;/td&gt;
          &lt;td&gt;2.57&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;So it&amp;rsquo;s settled. You wouldn&amp;rsquo;t save anything juicing watermelons unless you usually buy natural juice, which it turns out is quite pricey!&lt;/p&gt;
&lt;p&gt;This is how I got the price of a litre of watermelon water:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Water is 997.1 kg/m&lt;sup&gt;3&lt;/sup&gt; (0.9971 g/mL) at 25°C&lt;/li&gt;
&lt;li&gt;1000 mL * 0.9971 g/mL = 997.1 g water&lt;/li&gt;
&lt;li&gt;997.1 g / 91.45% = 1090 g watermelon&lt;/li&gt;
&lt;li&gt;1.090 kg * 96 c/kg = 1.05 c/L for watermelon water.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;This is not science&lt;/strong&gt;: I ignored the watermelon rind, and the 6.2 g / 100 g of sugars which would be dissolved in the water. If anybody juices a watermelon in a lab then I will revise these numbers.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Samoan Language Section Update</title>
        <link>https://mike42.me/blog/2012-01-samoan-language-section</link>
        <pubDate>Tue, 17 Jan 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-01-samoan-language-section</guid>
        <description>&lt;p&gt;I&amp;rsquo;ve now uploaded my Samoan vocabulary (~1200 words), and unfinished introductory guide. The audio works in Firefox on Ubuntu, but I haven&amp;rsquo;t tested it in other browsers.&lt;/p&gt;
&lt;p&gt;I have around a thousand words and a few hundred examples which I haven&amp;rsquo;t recorded, and the guide/phrases section contains many unfinished sections. If you are a native speaker of Samoan, or are interested in helping, then I would be interested to hear from you! My contact details can be found on the &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/about/&#34; &gt;about page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can find the section at: &lt;a class=&#34;link&#34; href=&#34;https://samoan.ws/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://samoan.ws/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; I&amp;rsquo;ve made MP3 versions of the audio files, and they can now play in all major browsers.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Converting Numbers To Words in PHP</title>
        <link>https://mike42.me/blog/2012-01-converting-numbers-to-words-in-php</link>
        <pubDate>Mon, 16 Jan 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-01-converting-numbers-to-words-in-php</guid>
        <description>&lt;p&gt;This is a straightforward coding task.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m working on some maths code in PHP, and need a function to output &amp;ldquo;twenty-five&amp;rdquo; for 25, &amp;ldquo;fifteen&amp;rdquo; for 15, etc. A quick google search pulled up a neat little &lt;a class=&#34;link&#34; href=&#34;http://pear.php.net/package/Numbers_Words&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;PEAR package&lt;/a&gt; which can do this.&lt;/p&gt;
&lt;p&gt;The results weren&amp;rsquo;t as flash as I&amp;rsquo;d hoped though. We ended up with this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;894: eight hundred ninety-four
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So it turns out that the PEAR class doesn&amp;rsquo;t print commas or the word &amp;lsquo;and&amp;rsquo; in its numbers. We will be feeding our numbers to &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/Festival_Speech_Synthesis_System&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;festival&lt;/a&gt;, and also using them for maths questions written in Australian English. Those pesky ands and commas are a &lt;em&gt;must&lt;/em&gt; for this project, so the current output is not good enough:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;9539: nine thousand five hundred thirty-nine
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Instead, I need:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;9539: nine thousand, five hundred and thirty-nine
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I found some commented out code, and tried my own modifications, but it wasn&amp;rsquo;t working right, so I scrapped the PEAR class and started from scratch, using Wikipedia to populate the lists:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/Names_of_large_numbers&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Names of large numbers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/English_numerals&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;English numerals&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The results were a great improvement. It took about 300 lines to replace the class, and it handles ordinal numbers too. (&amp;lsquo;1st&amp;rsquo; = &amp;lsquo;first&amp;rsquo;, &amp;lsquo;100th = one hundredth&amp;rsquo;, etc). I didn&amp;rsquo;t re-implement the currency feature in the PEAR class.&lt;/p&gt;
&lt;p&gt;To download the replacement class, click &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2012-01-converting-numbers-to-words-in-php/Numbers_Words.txt&#34; &gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s simple enough to use, just express ridiculous numbers or long decimals as strings to avoid errors. See this example for features:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;include&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Numbers_Words.php&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// one
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Numbers_Words&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;toWords&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;newline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// two
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Numbers_Words&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;toWords&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;newline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// twenty-five
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Numbers_Words&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;toWords&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;25&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;newline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// one thousand
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Numbers_Words&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;toWords&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;newline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// one thousand and one
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Numbers_Words&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;toWords&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1001&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;newline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// one hundred thousand and one
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Numbers_Words&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;toWords&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;100001&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;newline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// one hundred and twenty-three million, four hundred and fifty-six thousand, seven hundred and eighty-nine
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Numbers_Words&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;toWords&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;123 456 789&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;newline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// thirty-six point nine seven
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Numbers_Words&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;toWords&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;36.97&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;newline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cm&#34;&gt;/* nine novemvigintillion, eight hundred and seventy-two octovigintillion, three hundred and fourty-eight septemvigintillion,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;	nine hundred and seventy-two sesvigintillion, four hundred and ninety-two quinquavigintillion,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;	three hundred and eighty-four quattuorvigintillion, nine hundred and two tresvigintillion,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;	three hundred and eighty-four duovigintillion, two hundred and ninety unvigintillion, three hundred and eighty-four vigintillion,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;	two hundred and ninety novemdecillion, three hundred and fourty-two octodecillion, five hundred and sixty-three septendecillion,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;	four hundred and seventy-five sexdecillion, six hundred and thirty-four quindecillion, eight hundred and fifty-seven quattuordecillion,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;	four hundred and fifty-seven tredecillion, three hundred and fourty-nine duodecillion, eight hundred and fifty-seven undecillion,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;	two hundred and thirty-four decillion, five hundred and twenty-three nonillion, five hundred and thirty-four octillion,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;	eight hundred and fifty-three septillion, two hundred and ninety sextillion, four hundred and seventy-eight quintillion,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;	two hundred and ninety quadrillion, three hundred and fourty-seven trillion, two hundred and thirty-eight billion,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;	nine hundred and fourty-six million, five hundred and thirty-eight thousand, four hundred and seventy-six */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Numbers_Words&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;toWords&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;9872348972492384902384290384290342563475634857457349857234523534853290478290347238946538476&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;newline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// seventeenth
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Numbers_Words&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;toWords&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;17th&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;newline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// eight hundred and sixty-third
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Numbers_Words&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;toWords&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;863rd&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;newline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// negative seventy-eight point four
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Numbers_Words&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;na&#34;&gt;toWords&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;-78.4&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;newline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;newline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Using correct strings makes synthetic voices much less annoying, and hopefully provides a small improvement to the user experience.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Using speech synthesis in AGI apps</title>
        <link>https://mike42.me/blog/2012-01-using-speech-synthesis-in-agi-apps</link>
        <pubDate>Mon, 16 Jan 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-01-using-speech-synthesis-in-agi-apps</guid>
        <description>&lt;p&gt;For some of my telephone apps, stringing together pre-recorded messages is a pain, and it&amp;rsquo;s not even useful for more dynamic content.&lt;/p&gt;
&lt;p&gt;This blog post is a quick write-up of how I got PHP to do sound output via &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/Festival_Speech_Synthesis_System&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;festival&lt;/a&gt;, whilst using the asterisk AGI.&lt;/p&gt;
&lt;p&gt;First, I made a folder called &lt;code&gt;agi&lt;/code&gt; in my &lt;code&gt;/var/lib/asterisk/sounds/en/&lt;/code&gt;. This is where we will cache sound files.&lt;/p&gt;
&lt;p&gt;This shell script makes a sound file with your text, and saves it in that directory:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; text2wave -otype ulaw -o /var/lib/asterisk/sounds/en/agi/&lt;span class=&#34;nv&#34;&gt;$2&lt;/span&gt;.ulaw
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For the PHP side, we just use &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/MD5&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;MD5&lt;/a&gt; to name the files based on their contents, and only run the shell script if no file has been created with the text we want.&lt;/p&gt;
&lt;p&gt;In this project, &lt;code&gt;$agi&lt;/code&gt; refers to an instance of &lt;a class=&#34;link&#34; href=&#34;http://phpagi.sourceforge.net/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;PHP AGI&lt;/a&gt;(highly recommended)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sayNow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$escape&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;global&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$agi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$sounds_path&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/var/lib/asterisk/sounds/en/agi/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$agi_path&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/var/lib/asterisk/agi-bin/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$fn&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;md5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$string&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str_replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;, &amp;#34;&amp;#34;, &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$string&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$string&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; = str_replace(&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;, &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$string&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$string&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; = str_replace(&amp;#34;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;, &amp;#34;&amp;#34;, &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$string&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$string&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; = str_replace(&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34; slash &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;file_exists&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$sounds_path$fn&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;system&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$agi_path$common&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/sound.sh &amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$string&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$fn&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$agi&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;stream_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$sounds_path$fn&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$escape&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This makes sound output &lt;i&gt;at least a million&lt;/i&gt; times easier. We use it like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$a = sayNow(&amp;#34;Enter the number, then press hash&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s all there is to it. I should probably also set up a &lt;code&gt;cron&lt;/code&gt; job to clear the sound files at the end of each week.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Scripting Windows Shares</title>
        <link>https://mike42.me/blog/2012-01-scripting-windows-shares</link>
        <pubDate>Thu, 12 Jan 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-01-scripting-windows-shares</guid>
        <description>&lt;p&gt;As much as I try to avoid it, sometimes I need to use Windows servers, and windows &lt;code&gt;.bat&lt;/code&gt; files aren&amp;rsquo;t exactly the pinnacle of scripting languages. This post is about bulk-sharing home directories with consistent permissions.&lt;/p&gt;
&lt;p&gt;I decided to solve this by writing a PHP script to &lt;em&gt;generate&lt;/em&gt; a batch file, rather than use VB script.&lt;/p&gt;
&lt;p&gt;This crude script will make a batch file to share every subdirectory (in this case, hundreds of users&amp;rsquo; home directories), and also delete &lt;code&gt;desktop.ini&lt;/code&gt; from each of them. Save the code below as &lt;code&gt;magic.php&lt;/code&gt;, run it, and then run &lt;code&gt;tricks.bat&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$stuff&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;whats_here&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$tricks&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;fopen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;tricks.bat&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;w&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;foreach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$stuff&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$folder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$line&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;do_things&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$folder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;fwrite&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$tricks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;fclose&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$tricks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;do_things&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$folder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$things&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;:: &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$folder\r\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$things&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;net share &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$folder&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; /DELETE&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\r\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$things&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;net share &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$folder&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;=&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;getcwd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$folder&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; /GRANT:EVERYONE,FULL&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\r\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$things&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;del /Q &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$folder\desktop&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;.ini&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\r\n\r\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$things&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;whats_here&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* List directories in this one */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$here&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;opendir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;getcwd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;$dir&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;while&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$subdir&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;readdir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$here&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;is_dir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$subdir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$subdir&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$subdir&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;..&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nv&#34;&gt;$dir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$subdir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;closedir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$here&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$dir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As a side note, &lt;code&gt;/GRANT:EVERYONE,FULL&lt;/code&gt; is safe in this environment because ACLs are used for access control,&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve heard that &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/Windows_PowerShell&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Windows PowerShell&lt;/a&gt; is useful once you get used to it, but it&amp;rsquo;s not a useful skill outside of Windows admin, so for now a couple of PHP scripts will have to do.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Loading OEIS integer sequences</title>
        <link>https://mike42.me/blog/2012-01-loading-integer-sequences</link>
        <pubDate>Fri, 06 Jan 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-01-loading-integer-sequences</guid>
        <description>&lt;p&gt;To show that interpreted languages can be plenty fast when used well, I&amp;rsquo;m posting this example.&lt;/p&gt;
&lt;p&gt;Take the &lt;a class=&#34;link&#34; href=&#34;http://oeis.org&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;On-line Encyclopedia of Integer Sequences&lt;/a&gt; database, which is a collection of integer sequences. That means lists of numbers. You can get a file from &lt;a class=&#34;link&#34; href=&#34;http://oeis.org/stripped.gz&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://oeis.org/stripped.gz&lt;/a&gt;, which contains the first few numbers of each sequence. The file as at the time of writing file extracts to about 38MB.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2012-01-loading-integer-sequences/2012-01-06-oeis.png&#34;
	width=&#34;196&#34;
	height=&#34;244&#34;
	srcset=&#34;https://mike42.me/blog/2012-01-loading-integer-sequences/2012-01-06-oeis_hu_357f880db6a0d85d.png 480w, https://mike42.me/blog/2012-01-loading-integer-sequences/2012-01-06-oeis_hu_ed1a3be3383c425.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;80&#34;
		data-flex-basis=&#34;192px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I need to do lookups in this file for a program I&amp;rsquo;m writing, and that program is in PHP. I want to be able to look up sequences based on their A-number, like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$primes = oeis(&amp;#34;A000040&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$fibonacci = oeis(&amp;#34;A000045&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we&amp;rsquo;re economical about it, then even this large-ish file can be parsed in fractions of a second. Here&amp;rsquo;s how we do it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* This code needs an extract of the OEIS database to operate.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;	I got a copy from [http://oeis.org/stripped.gz](http://oeis.org/stripped.gz)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;	Just extract that to this folder for lookups */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;oeis&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$number&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;cm&#34;&gt;/* Return an array of values based on a sequence&amp;#39;s OEIS number */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$number&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;strtoupper&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$number&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$fp&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;fopen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;stripped&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;while&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$ln&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;fgets&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$fp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;cm&#34;&gt;/* Find this sequence and break the loop */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;substr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$ln&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;strlen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$number&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$number&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;nv&#34;&gt;$res&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$ln&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;fclose&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$fp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;cm&#34;&gt;/* Exit if we haven&amp;#39;t got anything */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;isset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$res&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$rv&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;explode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$ln&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;cm&#34;&gt;/* Split lines into left and right of space */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$ln&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;trim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$rv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$ln&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;substr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$ln&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;strlen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$ln&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;cm&#34;&gt;/* Slices off extra commas on sides */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nv&#34;&gt;$rv&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;explode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;,&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$ln&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;cm&#34;&gt;/* Split by commas */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$rv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that we don&amp;rsquo;t use &lt;code&gt;explode()&lt;/code&gt; until &lt;em&gt;after&lt;/em&gt; we have found the line we need, and also note that &lt;code&gt;file_get_contents()&lt;/code&gt; is not used at all. (As strings get larger they will bog you down in any language).&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Parsing Asterisk Configuration</title>
        <link>https://mike42.me/blog/2012-01-parsing-asterisk-configuration-files</link>
        <pubDate>Thu, 05 Jan 2012 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2012-01-parsing-asterisk-configuration-files</guid>
        <description>&lt;p&gt;If you are writing integrations for &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/Asterisk_PBX&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Asterisk PBX&lt;/a&gt;, you may feel the need to create an internal telephone directory.&lt;/p&gt;
&lt;p&gt;Today I&amp;rsquo;ve been putting together &lt;em&gt;Phonebook&lt;/em&gt;, a web-based phonebook which pulls data from an asterisk server. I used &lt;a class=&#34;link&#34; href=&#34;http://www.jqtouch.com/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;JQTouch&lt;/a&gt; for the interface, with &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/PHP&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;PHP&lt;/a&gt; to process data files. The system also use a &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/Comma-separated_values&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;CSV&lt;/a&gt; file exported from our &lt;a class=&#34;link&#34; href=&#34;http://www.google.com/apps/intl/en/business/gmail.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;hosted gmail&lt;/a&gt; to ensure that people&amp;rsquo;s names are displayed consistently between the email and phone directory.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2012-01-parsing-asterisk-configuration-files/2012-01-06-phonebook.jpg&#34;
	width=&#34;300&#34;
	height=&#34;523&#34;
	srcset=&#34;https://mike42.me/blog/2012-01-parsing-asterisk-configuration-files/2012-01-06-phonebook_hu_25b2a53f739cdca4.jpg 480w, https://mike42.me/blog/2012-01-parsing-asterisk-configuration-files/2012-01-06-phonebook_hu_88131526f98703a5.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;‘Phonebook’ web app&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;57&#34;
		data-flex-basis=&#34;137px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;the-configuration&#34;&gt;The configuration
&lt;/h2&gt;&lt;p&gt;Asterisk&amp;rsquo;s configuration files are &lt;a class=&#34;link&#34; href=&#34;http://en.wikipedia.org/wiki/INI_file&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;INI&lt;/a&gt;-like, and you&amp;rsquo;ll find them in &lt;code&gt;/etc/asterisk/&lt;/code&gt; on most systems.&lt;/p&gt;
&lt;p&gt;Just one important thing though, asterisk lets you use brackets &lt;code&gt;( )&lt;/code&gt; in caller-IDs or other fields, which will cause PHP&amp;rsquo;s &lt;a class=&#34;link&#34; href=&#34;http://php.net/manual/en/function.parse-ini-file.php&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;parse_ini_file()&lt;/a&gt; function fail, since that is a syntax error in the format it is expecting.&lt;/p&gt;
&lt;p&gt;To save yourself some trouble, this is a class which I wrote, which will load INI data into an associative array:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;ns_ini_parser&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Mike&amp;#39;s non-standard INI parser for asterisk files. https://mike42.me
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;        Note that PHP&amp;#39;s parse_ini_file will die with a syntax error on key = value (bracket), which makes it unsuitable. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;parse_string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$lines&lt;/span&gt;        &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;explode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$section&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$result&lt;/span&gt;        &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;foreach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$lines&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nv&#34;&gt;$line&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;trim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$line&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;substr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;cm&#34;&gt;/* Comment, no action */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;elseif&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;substr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;[&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;  &lt;span class=&#34;cm&#34;&gt;/* [section] */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nv&#34;&gt;$l&lt;/span&gt;          &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;strlen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nv&#34;&gt;$line&lt;/span&gt;          &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;trim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;substr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$l&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;    &lt;span class=&#34;cm&#34;&gt;/* Strip brackets */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nv&#34;&gt;$section&lt;/span&gt;      &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;isset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;nv&#34;&gt;$result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;                &lt;span class=&#34;cm&#34;&gt;/* key = val */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nv&#34;&gt;$parts&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;explode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;=&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nv&#34;&gt;$key&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;trim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$parts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;    &lt;span class=&#34;cm&#34;&gt;/* The key is everything left of the equal */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nx&#34;&gt;unset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$parts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;    &lt;span class=&#34;cm&#34;&gt;/* Got that, unset it */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nv&#34;&gt;$val&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;trim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;=&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$parts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;    &lt;span class=&#34;cm&#34;&gt;/* Value is everything on the righht */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nv&#34;&gt;$result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;][&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;parse_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;$string&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;file_get_contents&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$this&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;parse_string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The example usage below will list user&amp;rsquo;s extensions next to their caller ID, which you could use as the basis for a web phonebook:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Example PHP code to parse asterisk configuration */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$config_parser&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ns_ini_parser&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$users&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$config_parser&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;parse_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/etc/asterisk/users.conf&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;foreach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$users&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;is_numeric&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;cm&#34;&gt;/* Only show numbers, not other sections */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;lt;a href=&amp;#34;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;tel&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$id&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;gt;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;$id&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;lt;/a&amp;gt; &amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;fullname&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;lt;br /&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I don&amp;rsquo;t think it gets easier than that! I&amp;rsquo;ll post the rest once you can manage the contacts as well.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Some scripts to make word puzzles</title>
        <link>https://mike42.me/blog/2011-08-some-scripts-to-make-word-puzzles</link>
        <pubDate>Sun, 21 Aug 2011 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2011-08-some-scripts-to-make-word-puzzles</guid>
        <description>&lt;p&gt;I&amp;rsquo;ve put together &lt;a href=&#34;https://mike42.me/blog/words/&#34;&gt;a couple of PHP scripts&lt;/a&gt; to make puzzles. The humble find-a-word, a word scrambler, and a cipher.&lt;/p&gt;
&lt;p&gt;The output is just HTML, so you can include them on web-pages if you like. Look there&amp;rsquo;s one right here!&lt;/p&gt;


&lt;style&gt;
.find-a-word td { height: 1.5rem; width: 1.5rem; border: none; }
.find-a-word tr { background-color: transparent !important; }
.find-a-word {padding: 1rem;}
.find-a-word table {
    border-collapse: collapse;
    margin-left: auto;
    margin-right: auto;
    margin-bottom: 0;
    width: auto;
}
.find-a-word table {
     border: 1px solid #000;
    [data-scheme=&#39;dark&#39;] &amp; {
        border: 1px solid #fff;
    }
}
.word-here {
	background-color: #ff0;
	[data-scheme=&#39;dark&#39;] &amp; {
		color: #000;
	}
}
&lt;/style&gt;
&lt;div class=&#34;find-a-word&#34;&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;td&gt;Q&lt;/td&gt;
		&lt;td class=&#34;word-here&#34;&gt;M&lt;/td&gt;
		&lt;td&gt;Q&lt;/td&gt;
		&lt;td&gt;V&lt;/td&gt;
		&lt;td&gt;O&lt;/td&gt;
		&lt;td&gt;U&lt;/td&gt;
		&lt;td&gt;F&lt;/td&gt;
		&lt;td&gt;C&lt;/td&gt;
		&lt;td&gt;D&lt;/td&gt;
		&lt;td&gt;P&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;Q&lt;/td&gt;
		&lt;td&gt;L&lt;/td&gt;
		&lt;td class=&#34;word-here&#34;&gt;I&lt;/td&gt;
		&lt;td&gt;E&lt;/td&gt;
		&lt;td&gt;U&lt;/td&gt;
		&lt;td&gt;N&lt;/td&gt;
		&lt;td&gt;E&lt;/td&gt;
		&lt;td&gt;E&lt;/td&gt;
		&lt;td&gt;B&lt;/td&gt;
		&lt;td&gt;L&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;U&lt;/td&gt;
		&lt;td&gt;R&lt;/td&gt;
		&lt;td&gt;T&lt;/td&gt;
		&lt;td class=&#34;word-here&#34;&gt;C&lt;/td&gt;
		&lt;td&gt;B&lt;/td&gt;
		&lt;td&gt;X&lt;/td&gt;
		&lt;td&gt;N&lt;/td&gt;
		&lt;td class=&#34;word-here&#34;&gt;P&lt;/td&gt;
		&lt;td&gt;Q&lt;/td&gt;
		&lt;td&gt;B&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;C&lt;/td&gt;
		&lt;td&gt;N&lt;/td&gt;
		&lt;td&gt;Y&lt;/td&gt;
		&lt;td&gt;W&lt;/td&gt;
		&lt;td class=&#34;word-here&#34;&gt;H&lt;/td&gt;
		&lt;td&gt;E&lt;/td&gt;
		&lt;td&gt;Y&lt;/td&gt;
		&lt;td class=&#34;word-here&#34;&gt;U&lt;/td&gt;
		&lt;td&gt;X&lt;/td&gt;
		&lt;td&gt;T&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td class=&#34;word-here&#34;&gt;S&lt;/td&gt;
		&lt;td&gt;X&lt;/td&gt;
		&lt;td&gt;R&lt;/td&gt;
		&lt;td&gt;S&lt;/td&gt;
		&lt;td&gt;V&lt;/td&gt;
		&lt;td class=&#34;word-here&#34;&gt;A&lt;/td&gt;
		&lt;td&gt;C&lt;/td&gt;
		&lt;td class=&#34;word-here&#34;&gt;Z&lt;/td&gt;
		&lt;td&gt;D&lt;/td&gt;
		&lt;td&gt;K&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;B&lt;/td&gt;
		&lt;td class=&#34;word-here&#34;&gt;E&lt;/td&gt;
		&lt;td&gt;Z&lt;/td&gt;
		&lt;td&gt;Z&lt;/td&gt;
		&lt;td&gt;S&lt;/td&gt;
		&lt;td&gt;Z&lt;/td&gt;
		&lt;td class=&#34;word-here&#34;&gt;E&lt;/td&gt;
		&lt;td class=&#34;word-here&#34;&gt;Z&lt;/td&gt;
		&lt;td&gt;M&lt;/td&gt;
		&lt;td&gt;P&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td class=&#34;word-here&#34;&gt;F&lt;/td&gt;
		&lt;td&gt;Q&lt;/td&gt;
		&lt;td class=&#34;word-here&#34;&gt;A&lt;/td&gt;
		&lt;td&gt;Z&lt;/td&gt;
		&lt;td&gt;R&lt;/td&gt;
		&lt;td&gt;O&lt;/td&gt;
		&lt;td&gt;F&lt;/td&gt;
		&lt;td class=&#34;word-here&#34;&gt;L&lt;/td&gt;
		&lt;td&gt;Q&lt;/td&gt;
		&lt;td&gt;M&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;K&lt;/td&gt;
		&lt;td class=&#34;word-here&#34;&gt;I&lt;/td&gt;
		&lt;td&gt;F&lt;/td&gt;
		&lt;td class=&#34;word-here&#34;&gt;R&lt;/td&gt;
		&lt;td&gt;L&lt;/td&gt;
		&lt;td&gt;S&lt;/td&gt;
		&lt;td&gt;Y&lt;/td&gt;
		&lt;td class=&#34;word-here&#34;&gt;E&lt;/td&gt;
		&lt;td&gt;U&lt;/td&gt;
		&lt;td&gt;H&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;K&lt;/td&gt;
		&lt;td&gt;M&lt;/td&gt;
		&lt;td class=&#34;word-here&#34;&gt;N&lt;/td&gt;
		&lt;td&gt;I&lt;/td&gt;
		&lt;td class=&#34;word-here&#34;&gt;C&lt;/td&gt;
		&lt;td&gt;W&lt;/td&gt;
		&lt;td&gt;H&lt;/td&gt;
		&lt;td&gt;T&lt;/td&gt;
		&lt;td&gt;X&lt;/td&gt;
		&lt;td&gt;V&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td class=&#34;word-here&#34;&gt;W&lt;/td&gt;
		&lt;td class=&#34;word-here&#34;&gt;O&lt;/td&gt;
		&lt;td class=&#34;word-here&#34;&gt;R&lt;/td&gt;
		&lt;td class=&#34;word-here&#34;&gt;D&lt;/td&gt;
		&lt;td&gt;N&lt;/td&gt;
		&lt;td class=&#34;word-here&#34;&gt;H&lt;/td&gt;
		&lt;td&gt;A&lt;/td&gt;
		&lt;td&gt;C&lt;/td&gt;
		&lt;td&gt;D&lt;/td&gt;
		&lt;td&gt;Q&lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;


&lt;p&gt;I still need to write a command-line interface, as making a find-a-word large enough to hold every single word in the English dictionary is a bit too much for one page-load.&lt;/p&gt;
&lt;p&gt;But hey does that sound fun or what? I&amp;rsquo;m going to market &lt;em&gt;word-search wallpaper!&lt;/em&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Write something on a chessboard</title>
        <link>https://mike42.me/blog/2011-07-write-something-on-a-chessboard</link>
        <pubDate>Fri, 29 Jul 2011 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2011-07-write-something-on-a-chessboard</guid>
        <description>&lt;p&gt;I&amp;rsquo;ve put together a little algorithm called &lt;strong&gt;chess104&lt;/strong&gt;. It will let you encode data as positions of chess pieces on a board (104 bits of data, hence the name).&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2011-07-write-something-on-a-chessboard/2025-08-chess-board-example.png&#34;
	width=&#34;897&#34;
	height=&#34;625&#34;
	srcset=&#34;https://mike42.me/blog/2011-07-write-something-on-a-chessboard/2025-08-chess-board-example_hu_d5fd74fb34cb8aa3.png 480w, https://mike42.me/blog/2011-07-write-something-on-a-chessboard/2025-08-chess-board-example_hu_e3fc61f58af58774.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;An example of a chess board containing a hidden message&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;143&#34;
		data-flex-basis=&#34;344px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;That works out to 20 characters using a squashy 5-bit encoding, but there are &lt;a class=&#34;link&#34; href=&#34;../chess/index.php?action=encodings&#34; &gt;other&lt;/a&gt; options too if you really need to write &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/chess/index.php?action=encode&amp;amp;text=C0FFEEC0FFEEC0FFEEC0FFEEEE&amp;amp;encoding=hex&#34; &gt;&amp;ldquo;COFFEE&amp;rdquo;&lt;/a&gt; in efficient hexadecimal.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/chess/&#34; &gt;Write something on a chessboard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;An example board: &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/chess/?fen=8%2F1bR1pP2%2FNp1rB1P1%2F3RkK1B%2Fp1p2pQp%2FPPP3pP%2Fr1npPn2%2F1N1P2qb&amp;#43;w&amp;#43;KQkq&amp;#43;-&amp;#43;0&amp;#43;1&amp;amp;action=decode&amp;amp;encoding=latin-1&#34; &gt;&amp;ldquo;Mike was here&amp;rdquo;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If I can find a speedy way to encode more data, there might be a sequel to this. 104 bits is nowhere near the limit, but my other ideas were too much for my netbook to handle, which may also make them bad candidates for running as a web app.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Samoan Language Resources Section Started</title>
        <link>https://mike42.me/blog/2011-06-samoan-language-resources-section-started</link>
        <pubDate>Sat, 25 Jun 2011 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2011-06-samoan-language-resources-section-started</guid>
        <description>&lt;p&gt;I&amp;rsquo;ve put the beginnings of my Samoan Language section online. It&amp;rsquo;s still about 6-months away from becoming useful, but you can see the start of it &lt;a class=&#34;link&#34; href=&#34;https://samoan.ws/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The story is:&lt;/strong&gt; I wanted to put my language notes online, but in the 21&lt;sup&gt;st&lt;/sup&gt; century, there&amp;rsquo;s no way I&amp;rsquo;d do it without audio, and hyperlinks to a good dictionary.&lt;/p&gt;
&lt;p&gt;There doesn&amp;rsquo;t seem to be anything like that online yet, so I took the liberty of creating a neat database combining the words with audio, definitions, and examples which can be embedded in the notes.&lt;/p&gt;
&lt;p&gt;That opens up a lot of ideas for other things, but for now I still have a lot of data to collect. Back to work!&lt;/p&gt;
</description>
        </item>
        <item>
        <title>I blame tetrads!</title>
        <link>https://mike42.me/blog/2011-04-i-blame-tetrads</link>
        <pubDate>Sat, 09 Apr 2011 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2011-04-i-blame-tetrads</guid>
        <description>&lt;p&gt;If you play too much Tetris, then you should check out the new subpage: &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/tetrad/&#34; &gt;The Tetrad Corner&lt;/a&gt;. It&amp;rsquo;s a collection of things I&amp;rsquo;ve made this week about the shapes used in tetris (&amp;rsquo;tetrads&amp;rsquo;, also called &amp;rsquo;tetrominos&amp;rsquo;).&lt;/p&gt;
&lt;p&gt;The original idea was that it would be cool to have a tetradic phone password. That is, your password makes a Tetris shape on the keypad. I was bored enough this week to actually write a little script for it, along with a PHP class for rotating the blocks, rendering them as a HTML table, and so on.&lt;/p&gt;
&lt;p&gt;It turned out alright, but fearing that I had begun something as time-consuming as tetris itself, I banished it to a single-page sub-site. The source code is there if you want those HTML-tetrads on a webpage (I don&amp;rsquo;t!):&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2011-04-i-blame-tetrads/2011-04-10-tetrad-row.png&#34;
	width=&#34;547&#34;
	height=&#34;42&#34;
	srcset=&#34;https://mike42.me/blog/2011-04-i-blame-tetrads/2011-04-10-tetrad-row_hu_e80addce47d9c44f.png 480w, https://mike42.me/blog/2011-04-i-blame-tetrads/2011-04-10-tetrad-row_hu_7902b927074745a7.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;HTML-generated tetrads&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;1302&#34;
		data-flex-basis=&#34;3125px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Now what I do want is a few tetris blocks for my desk, so I made up some nets to print out and cut up. Now I can make a small paper Tetris game! (PDF version &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/blog/2011-04-i-blame-tetrads/tetrad-nets.pdf&#34; &gt;here&lt;/a&gt;). Neat, huh?&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2011-04-i-blame-tetrads/2011-04-10-tetrad-nets.png&#34;
	width=&#34;191&#34;
	height=&#34;222&#34;
	srcset=&#34;https://mike42.me/blog/2011-04-i-blame-tetrads/2011-04-10-tetrad-nets_hu_d0ac5a68701866e1.png 480w, https://mike42.me/blog/2011-04-i-blame-tetrads/2011-04-10-tetrad-nets_hu_dde1eb93643b5f7.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Tetrad nets&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;86&#34;
		data-flex-basis=&#34;206px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; I built these shapes today. There were two tabs missing on the nets (fixed!), so I cheated by using sticky tape. Click to enlarge the badly-colourised image.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2011-04-i-blame-tetrads/2011-04-12-tetris.jpg&#34;
	width=&#34;600&#34;
	height=&#34;429&#34;
	srcset=&#34;https://mike42.me/blog/2011-04-i-blame-tetrads/2011-04-12-tetris_hu_81a48bb42ed2ab14.jpg 480w, https://mike42.me/blog/2011-04-i-blame-tetrads/2011-04-12-tetris_hu_d37c3c2dde5d09ab.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;A tetris game in the palm of my hand&#34;
	
	
	
		class=&#34;gallery-image img-xs&#34; 
		data-flex-grow=&#34;139&#34;
		data-flex-basis=&#34;335px&#34;
	
&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Mike&#39;s Webserver v1.0</title>
        <link>https://mike42.me/blog/2010-11-mikes-webserver-v1-0</link>
        <pubDate>Tue, 02 Nov 2010 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2010-11-mikes-webserver-v1-0</guid>
        <description>&lt;p&gt;This is an old project of mine to make a webserver. It is fairly functional if a little incomplete. You can find it at &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/webserver/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://mike42.me/webserver/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2010-11-mikes-webserver-v1-0/mike-webserver-1.0.png&#34;
	width=&#34;824&#34;
	height=&#34;438&#34;
	srcset=&#34;https://mike42.me/blog/2010-11-mikes-webserver-v1-0/mike-webserver-1.0_hu_83150406c8b40c7a.png 480w, https://mike42.me/blog/2010-11-mikes-webserver-v1-0/mike-webserver-1.0_hu_a0982c23355913ed.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Mike’s Webserver at work&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;188&#34;
		data-flex-basis=&#34;451px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The source code is straightforward, and could be a useful reference if you are writing your own webserver. Hopefully with less bugs, of course.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Raycaster is not Windows-only after all</title>
        <link>https://mike42.me/blog/2010-11-raycaster-is-not-windows-only-after-all</link>
        <pubDate>Tue, 02 Nov 2010 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2010-11-raycaster-is-not-windows-only-after-all</guid>
        <description>&lt;p&gt;Somebody got my raycaster working on Ubuntu GNU/Linux, via WINE. Here is a screenshot:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2010-11-raycaster-is-not-windows-only-after-all/mike-raycaster-nix.png&#34;
	width=&#34;795&#34;
	height=&#34;515&#34;
	srcset=&#34;https://mike42.me/blog/2010-11-raycaster-is-not-windows-only-after-all/mike-raycaster-nix_hu_baf3ac93fef88f10.png 480w, https://mike42.me/blog/2010-11-raycaster-is-not-windows-only-after-all/mike-raycaster-nix_hu_96d9df9cab0f0b8f.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-lg&#34; 
		data-flex-grow=&#34;154&#34;
		data-flex-basis=&#34;370px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;You can find the Windows raycaster at &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/raycaster/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://mike42.me/raycaster/&lt;/a&gt;.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>An experiment in dynamic recipes</title>
        <link>https://mike42.me/blog/an-experiment-in-dynamic-recipes</link>
        <pubDate>Tue, 26 Oct 2010 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/an-experiment-in-dynamic-recipes</guid>
        <description>&lt;p&gt;Dynamic content doesn&amp;rsquo;t seem to have reached the field of culinary art yet - but it could have one very neat application:&lt;/p&gt;
&lt;p&gt;You tell a computer what ingredients you have, and it tells you what to make.&lt;/p&gt;
&lt;p&gt;As a small experiment, this PHP script (&lt;a class=&#34;link&#34; href=&#34;https://mike42.me/cordial/citrus.php?view=1&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;source code&lt;/a&gt;) will suggest fruit combinations for making citrus cordial, based on what fruit you have available. It will also tell you how much sugar, citric acid, and tartaric acid you will need.&lt;/p&gt;


&lt;iframe src=&#34;https://mike42.me/cordial/citrus.php&#34; height=&#34;500&#34; width=&#34;100%&#34; style=&#34;background: #fff&#34;&gt;&lt;/iframe&gt;


&lt;p&gt;If you live in a region with different citrus fruit available, then you would need to modify the fruit list at the top of the code and run a copy locally.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Mike&#39;s Raycaster - Version 0.04</title>
        <link>https://mike42.me/blog/mikes-raycaster-version-0.04</link>
        <pubDate>Mon, 18 Oct 2010 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/mikes-raycaster-version-0.04</guid>
        <description>&lt;p&gt;I&amp;rsquo;ve just finished writing up version 0.04 of my fairly buggy raycaster demonstration, which you can find at &lt;a class=&#34;link&#34; href=&#34;https://mike42.me/raycaster/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://mike42.me/raycaster/&lt;/a&gt;. The source code is also available from there. This one will only work on Windows.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/mikes-raycaster-version-0.04/2010-10-19-mike-raycaster-04.png&#34;
	width=&#34;512&#34;
	height=&#34;420&#34;
	srcset=&#34;https://mike42.me/blog/mikes-raycaster-version-0.04/2010-10-19-mike-raycaster-04_hu_9dc4b2b7b4640cee.png 480w, https://mike42.me/blog/mikes-raycaster-version-0.04/2010-10-19-mike-raycaster-04_hu_c92714a8e2b74ffe.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Mike’s Raycaster at work&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;121&#34;
		data-flex-basis=&#34;292px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;The controls in this version are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Movement:&lt;/strong&gt; Up, Down, Left, Right arrows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Return to start:&lt;/strong&gt; Enter (return).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Debug mode:&lt;/strong&gt; Space bar.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The rendering bugs in this version will need a partial re-write to fix, so look out for the 0.05 release.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Strange problems from corrupt files</title>
        <link>https://mike42.me/blog/2007-08-strange-problems-from-corrupt-files</link>
        <pubDate>Mon, 06 Aug 2007 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2007-08-strange-problems-from-corrupt-files</guid>
        <description>&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2007-08-strange-problems-from-corrupt-files/2007-08-strange-gzip-problem.png&#34;
	width=&#34;642&#34;
	height=&#34;97&#34;
	srcset=&#34;https://mike42.me/blog/2007-08-strange-problems-from-corrupt-files/2007-08-strange-gzip-problem_hu_1d5be7b63e1806a4.png 480w, https://mike42.me/blog/2007-08-strange-problems-from-corrupt-files/2007-08-strange-gzip-problem_hu_3e3dcebe17b712da.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;2007-08-strange-gzip-problem.png&#34;
	
	
	
		class=&#34;gallery-image &#34; 
		data-flex-grow=&#34;661&#34;
		data-flex-basis=&#34;1588px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m upgrading from Firefox 0.x to 2.x on one of my computers. Decompressing the downloaded file seemed to be taking far too long, so I took a look at what was up. Somehow, it seems that the incomplete download of 2.4MB (the whole thing should be around 9MB) managed to cause gzip to write out 521MB of data before I stopped it.&lt;/p&gt;
&lt;p&gt;The moral of the story? Always check the MD5 sums.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>This error message is beyond me...</title>
        <link>https://mike42.me/blog/2007-08-this-error-message-is-beyond-me</link>
        <pubDate>Thu, 02 Aug 2007 00:00:00 +0000</pubDate>
        
        <guid>https://mike42.me/blog/2007-08-this-error-message-is-beyond-me</guid>
        <description>&lt;p&gt;&lt;img src=&#34;https://mike42.me/blog/2007-08-this-error-message-is-beyond-me/2007-08-keyboard-error-cropped.jpg&#34;
	width=&#34;150&#34;
	height=&#34;148&#34;
	srcset=&#34;https://mike42.me/blog/2007-08-this-error-message-is-beyond-me/2007-08-keyboard-error-cropped_hu_e4bab377499dc651.jpg 480w, https://mike42.me/blog/2007-08-this-error-message-is-beyond-me/2007-08-keyboard-error-cropped_hu_495ad517881ce136.jpg 1024w&#34;
	loading=&#34;lazy&#34;
	
	
	
		class=&#34;gallery-image img-xxs&#34; 
		data-flex-grow=&#34;101&#34;
		data-flex-basis=&#34;243px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;I have seen this message more than I would like.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Keyboard Error&lt;/p&gt;
&lt;p&gt;Press F1 to Resume&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Seriously, whoever was cruel enough to invent an error message like this deserves a cookie for ingenuity.&lt;/p&gt;
</description>
        </item>
        
    </channel>
</rss>
