<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>mjt.me.uk</title>
 <link href="https://www.mjt.me.uk/atom.xml" rel="self"/>
 <link href="https://www.mjt.me.uk"/>
 <updated>2020-09-26T21:10:58+01:00</updated>
 <id>https://www.mjt.me.uk</id>
 <author>
   <name>Michael Tandy</name>
   <email>website@mjt.me.uk</email>
 </author>

 
 <entry>
   <title>Making the Macrosilicon MS2109 HDMI-to-USB capture device work on Linux</title>
   <link href="https://www.mjt.me.uk/posts/fixing-missing-macrosilicon-ms2109/"/>
   <updated>2020-09-26T00:00:00+01:00</updated>
   <id>https://www.mjt.me.uk/posts/fixing-missing-macrosilicon-ms2109</id>
   <content type="html">&lt;p&gt;I brought a cheap (£10) HDMI-to-USB2 capture device based on the Macrosilicon 2109 - but I encountered a problem where it didn&amp;#39;t appear at &lt;code&gt;/dev/video*&lt;/code&gt; when plugged in, despite &lt;code&gt;dmesg&lt;/code&gt; showing some recognition of the device.&lt;/p&gt;

&lt;p&gt;Fortunately, &lt;a href=&quot;https://bbs.archlinux.org/viewtopic.php?pid=1919811#p1919811&quot;&gt;Nikola_F on the Arch Linux forums&lt;/a&gt; had already found the problem and offered a solution: The device is wrongly being treated as a USB audio device. You can confirm this by checking four new symlinks appear in &lt;code&gt;ls -l /sys/bus/usb/drivers/snd-usb-audio/&lt;/code&gt; when you insert the device.&lt;/p&gt;

&lt;p&gt;To fix it, I created new udev rules (in a file like &lt;code&gt;/etc/udev/rules.d/91-hdmi-to-usb-ms2109.rules&lt;/code&gt; ) to apply Nikola_F&amp;#39;s fix automatically:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;# For HDMI-to-USB adaptor:
SUBSYSTEM==&amp;quot;usb&amp;quot;, DRIVER==&amp;quot;snd-usb-audio&amp;quot;, ATTRS{idProduct}==&amp;quot;2109&amp;quot;, ATTRS{idVendor}==&amp;quot;534d&amp;quot;, \
    RUN+=&amp;quot;/bin/sh -c &amp;#39;echo -n $kernel &amp;gt; /sys/bus/usb/drivers/snd-usb-audio/unbind&amp;#39;&amp;quot;

SUBSYSTEM==&amp;quot;usb&amp;quot;, DRIVER==&amp;quot;snd-usb-audio&amp;quot;, ATTRS{idProduct}==&amp;quot;2109&amp;quot;, ATTRS{idVendor}==&amp;quot;534d&amp;quot;, \
    ATTR{bInterfaceNumber}==&amp;quot;00&amp;quot;, RUN+=&amp;quot;/bin/sh -c &amp;#39;sleep 1; echo -n $kernel &amp;gt; /sys/bus/usb/drivers/uvcvideo/bind&amp;#39;&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Give it a &lt;code&gt;sudo udevadm control --reload-rules&lt;/code&gt; then unplug and replug, and it should start working.&lt;/p&gt;

&lt;p&gt;This disables the audio function of the HDMI-to-USB converter, but I wasn&amp;#39;t using it anyway. More careful rule-writing could probably solve that problem.&lt;/p&gt;

&lt;h2 id=&quot;other-hints-for-using-the-ms2109&quot;&gt;Other hints for using the MS2109&lt;/h2&gt;

&lt;p&gt;I was able to stream video from the device at 1080p with &lt;code&gt;ffplay -f video4linux2 -framerate 50 -video_size 1920x1080 -input_format mjpeg /dev/video0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The device seemed to struggle if mjpeg wasn&amp;#39;t used - presumably a lack of USB bandwidth. If you want to use it with software you can&amp;#39;t convince to ask for mjpeg, you can create a loopback camera and use ffmpeg to read mjpeg from the capture card and output regular video to the loopback camera, like so:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;sudo apt-get install ffmpeg v4l2loopback-utils

sudo modprobe v4l2loopback devices=1 video_nr=10 card_label=&amp;quot;LoopbackCam&amp;quot; exclusive_caps=1
ffmpeg -f video4linux2 -framerate 50 -video_size 1920x1080 -input_format mjpeg -i /dev/video0 -f v4l2 -pix_fmt yuv420p /dev/video10
&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;</content>
 </entry>
 
 <entry>
   <title>Streaming live video over Wifi from the Panasonic Lumix GX80</title>
   <link href="https://www.mjt.me.uk/posts/wifi-streaming-video-lumix-gx80/"/>
   <updated>2020-04-27T00:00:00+01:00</updated>
   <id>https://www.mjt.me.uk/posts/wifi-streaming-video-lumix-gx80</id>
   <content type="html">&lt;h2 id=&quot;summary-amp-background&quot;&gt;Summary &amp;amp; Background&lt;/h2&gt;

&lt;p&gt;The Panasonic Lumix GX80 is a mirrorless, interchangable lens micro four thirds camera. &lt;a href=&quot;https://twitter.com/chapperztv/status/996331824795279360?lang=en&quot;&gt;Some people have used it as a streaming webcam&lt;/a&gt; by connecting the camera&amp;#39;s HDMI output to a HDMI-to-USB capture card (cost ~£120). It also has wifi connectivity, and can be controlled remotely - including a live preview over wifi.&lt;/p&gt;

&lt;p&gt;I set out to see I could use that wifi live preview like a webcam.&lt;/p&gt;

&lt;p&gt;In summary, &lt;strong&gt;I was able to get it to work - but with a lot of caveats.&lt;/strong&gt; The live preview is 640x480 30fps and with some software trickery, I was able to use that video as a webcam in video calls.&lt;/p&gt;

&lt;h2 id=&quot;sample-output&quot;&gt;Sample output&lt;/h2&gt;

&lt;p&gt;This image is captured raw from the mjpeg stream:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/lumix-webcam/raw-single-jpeg.jpg&quot; alt=&quot;A single frame of camera output&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://fotoforensics.com/analysis.php?id=1fab6d98e1e4384f4509f9bb8cdfc9f3d66e750a.27013&quot;&gt;FotoForensics estimates&lt;/a&gt; its compression level as 49%. The video stream has a bandwidth of about 6.8 Mbps and runs at 30 frames per second (even if your camera is PAL and records video at 25fps)&lt;/p&gt;

&lt;h3 id=&quot;sample-video&quot;&gt;Sample video&lt;/h3&gt;

&lt;video autoplay loop muted width=&quot;640&quot; height=&quot;480&quot;&gt;
    &lt;source src=&quot;/assets/images/lumix-webcam/sample-video.webm&quot; type=&quot;video/webm&quot;&gt;
    Sorry, your browser doesn't support embedded videos.
&lt;/video&gt;

&lt;h2 id=&quot;quick-start&quot;&gt;Quick Start&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Install dependencies something like this (assumes you have java and maven already, if not install them too):&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;sudo apt-get install ffmpeg v4l2loopback-utils
sudo modprobe v4l2loopback devices=1 video_nr=10 card_label=&amp;quot;LoopbackCam&amp;quot; exclusive_caps=1
git clone git@github.com:michaeltandy/lumix-wifi-webcam.git
cd lumix-wifi-webcam
mvn package
sudo sysctl -w net.ipv4.ipfrag_time=5
# This undoes CVE-2018-5391 mitigation
sudo sysctl -w net.ipv4.ipfrag_high_thresh=4194304 
&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;Turn on your camera, and connect it to wifi. I recommend using your router&amp;#39;s WPS button so you don&amp;#39;t have to type a password on a camera touchscreen.&lt;/li&gt;
&lt;li&gt;Give your camera a fixed IP address in your router&amp;#39;s DHCP settings, and note down what it is.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;java -jar target/lumix-wifi-webcam.jar [your webcam&amp;#39;s IP]
&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;credit-where-it-39-s-due&quot;&gt;Credit where it&amp;#39;s due&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.personal-view.com/talks/discussion/6703/control-your-gh3-from-a-web-browser-now-with-video-/p1&quot;&gt;lenuisible for reporting the stream is a MJPEG video over UDP, and a Java stream viewer&lt;/a&gt; and &lt;a href=&quot;https://github.com/peci1/lumix-link-desktop&quot;&gt;Martin Pecka&lt;/a&gt; for keeping that alive and where I could find it. &lt;a href=&quot;https://www.eoshd.com/comments/topic/24995-would-you-perhaps-be-interested-in-a-different-gx8085-colour-profile/#comments&quot;&gt;BTM_Pix&lt;/a&gt; and &lt;a href=&quot;https://github.com/cleverfox/lumixproto&quot;&gt;Vladimir Goncharov&lt;/a&gt; for additional info on Lumix remote control.&lt;/p&gt;

&lt;h2 id=&quot;you-mentioned-a-lot-of-caveats&quot;&gt;You mentioned a lot of caveats?&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The resolution of 640x480 is nothing to write home about, and is quite heavily compressed.&lt;/li&gt;
&lt;li&gt;I encountered a latency of about 130ms - 4 frames - meaning sound and video are out of sync by an amount people will notice.&lt;/li&gt;
&lt;li&gt;The mjpeg-over-UDP protocol doesn&amp;#39;t work very well in the presence of dropped packets or link congestion. This can lead to seemingly random performance degredation. Mitigations for consequences of this have security implications.&lt;/li&gt;
&lt;li&gt;The GX80 can&amp;#39;t be powered by USB while it&amp;#39;s operating - so you need a &amp;#39;dummy battery&amp;#39; power supply if you don&amp;#39;t want your battery to run out (search for DMW-DCC11 if you want one)&lt;/li&gt;
&lt;li&gt;In the course of my experiments, I managed to trigger several bugs in the camera&amp;#39;s firmware - including one that froze the camera&amp;#39;s entire interface, &lt;em&gt;including the on/off switch&lt;/em&gt;, so I had to eject the battery to restart the camera. This doesn&amp;#39;t seem like a solid foundation for a stable video system.&lt;/li&gt;
&lt;li&gt;The GX80&amp;#39;s wifi interface has no security, except the fact most users will never connect it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;oddities-of-the-mjpeg-over-udp-protocol&quot;&gt;Oddities of the mjpeg-over-udp protocol&lt;/h2&gt;

&lt;p&gt;Each frame is a single UDP datagram - making each datagram much larger than the ethernet MTU, and leading to packet fragmentation.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/lumix-webcam/fragmented-udp.png&quot; alt=&quot;Wireshark screencapture&quot;&gt;&lt;/p&gt;

&lt;p&gt;Here we see a 27 kilobyte image split into 19 fragments. If any of those 19 fragments are lost, the frame is lost. If you&amp;#39;ve got slow wifi, this can happen a lot.&lt;/p&gt;

&lt;h3 id=&quot;variable-length-prefix&quot;&gt;Variable-length prefix&lt;/h3&gt;

&lt;p&gt;The mjpeg-over-UDP datagrams had a prefix before the JPEG data - usually of the same length, but occasionally varying. What&amp;#39;s going on with that?&lt;/p&gt;

&lt;p&gt;I reverse-engineered enough of the protocol to learn that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The length of the header is given in the header; there&amp;#39;s a 16-bit integer starting at index 30; add 32 to that and you&amp;#39;ve got the index of the first byte of the JPEG data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The reason the header varies in length is it contains info about things that cause the camera to show things on the screen (like face detecton and points selected by autofocus) and the number of such things can vary.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;ip-fragment-reassembly-queue-exhaustion&quot;&gt;IP fragment reassembly queue exhaustion&lt;/h3&gt;

&lt;p&gt;On Linux, the video stream would sometimes freeze for tens of seconds at a time, with UDP reads timing out as if no UDP traffic was being received - but Wireshark would indicate UDP packets were still arriving just fine.&lt;/p&gt;

&lt;p&gt;It turns out the Linux kernel has a queue of partly-reassembled IP packets, waiting around for the missing fragments to come in. In the default configuration this queue has a fixed size of ~260 kilobytes in memory, doesn&amp;#39;t discard stored contents for 30 seconds, and silently discards new packets when full.&lt;/p&gt;

&lt;p&gt;With 27 kilobytes per frame, 30 frames per second and a 260 kilobyte limit on fragmented packets, if 10 frames drop a single fragment within 30 seconds the UDP socket would receive nothing until the oldest fragmented packet had aged out of the queue.&lt;/p&gt;

&lt;p&gt;To work around this, I increased the fragment reassembly queue space - which undoes &lt;a href=&quot;https://security-tracker.debian.org/tracker/CVE-2018-5391&quot;&gt;CVE-2018-5391 mitigation&lt;/a&gt; but I deem that tolerable as I&amp;#39;m not running a public-facing server. I also reduced the fragment reassembly time from 30 seconds to 5.&lt;/p&gt;

&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/prism.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/components/prism-bash.min.js&quot;&gt;&lt;/script&gt;
</content>
 </entry>
 
 <entry>
   <title>Blacklisting your USB Webcam's built-in microphone in Linux</title>
   <link href="https://www.mjt.me.uk/posts/blacklisting-certain-microphones-linux/"/>
   <updated>2020-04-10T00:00:00+01:00</updated>
   <id>https://www.mjt.me.uk/posts/blacklisting-certain-microphones-linux</id>
   <content type="html">&lt;style&gt;
.highlightA { background-color:#5DDFE8; }
&lt;/style&gt;

&lt;h2 id=&quot;motivation&quot;&gt;Motivation&lt;/h2&gt;

&lt;p&gt;I&amp;#39;ve got a headset with a microphone, and a webcam with a built-in microphone too; I always want to use the headset microphone, but sometimes the OS or videoconferencing tools start up using the wrong one. &lt;/p&gt;

&lt;p&gt;The good news is Linux will let you disable your webcam&amp;#39;s microphone without disabling its video. I&amp;#39;ve done this successfully on Ubuntu 18.04&lt;/p&gt;

&lt;h2 id=&quot;how-it-39-s-done&quot;&gt;How it&amp;#39;s done&lt;/h2&gt;

&lt;p&gt;We&amp;#39;re going to do it with &lt;a href=&quot;https://projectgus.com/2014/09/blacklisting-a-single-usb-device-from-linux/&quot;&gt;udev-based USB device blacklisting&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, we find the USB VID and PID (&amp;#39;vendor ID&amp;#39; and &amp;#39;product ID&amp;#39;) for the webcam:&lt;/p&gt;

&lt;pre&gt;
$ lsusb
Bus 002 Device 002: ID 8087:8001 Intel Corp. 
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
[snip]
Bus 003 Device 002: ID 045e:0750 Microsoft Corp. Wired Keyboard 600
Bus 003 Device 009: ID &lt;span class=&quot;highlightA&quot;&gt;046d:0991&lt;/span&gt; Logitech, Inc. QuickCam Pro for Notebooks
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
&lt;/pre&gt;

&lt;p&gt;If it&amp;#39;s not obvious from &lt;code&gt;lsusb&lt;/code&gt; which device is your webcam, you can always hotplug and see which device disappears - and you can view lots of details of sound devices with &lt;code&gt;udevadm info -a /dev/snd/by-id/*&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We then create a new text file at &lt;code&gt;/etc/udev/rules.d/90-blacklist-webcam-sound.rules&lt;/code&gt; containing the following udev rule:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;# Disables webcam audio.
SUBSYSTEM==&amp;quot;usb&amp;quot;, DRIVER==&amp;quot;snd-usb-audio&amp;quot;, ATTRS{idVendor}==&amp;quot;046d&amp;quot;, ATTRS{idProduct}==&amp;quot;0991&amp;quot;, ATTR{authorized}=&amp;quot;0&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Then reload the rules with &lt;code&gt;sudo udevadm control --reload-rules&lt;/code&gt; unplug and replug your device - it should now appear as a camera but not a microphone.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Loading Symantec VIP Access credentials onto Yubikeys</title>
   <link href="https://www.mjt.me.uk/posts/yubikey-symantec-vip-access/"/>
   <updated>2020-03-29T00:00:00+00:00</updated>
   <id>https://www.mjt.me.uk/posts/yubikey-symantec-vip-access</id>
   <content type="html">&lt;style&gt;
.tokenId { background-color:#5DDFE8; }
.secret { background-color:#5DE87D; }
.tid2 { background-color:#ACE85D; }
.sec2 { background-color:#E85DE6; }
&lt;/style&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;You can generate &lt;a href=&quot;https://vip.symantec.com/&quot;&gt;Symantec VIP Access&lt;/a&gt; credentials and load them onto any Yubikey that supports TOTP or HOTP (i.e. any Yubikey that isn&amp;#39;t blue).&lt;/p&gt;

&lt;p&gt;&lt;small&gt;If you don&amp;#39;t already have a Yubikey, you might also consider a &lt;a href=&quot;https://www.amazon.com/dp/B07YGYLY9D&quot;&gt;Symantec VIP Hardware Authenticator&lt;/a&gt; which is less than half the price of the Yubikey I used - but I already have the Yubikey and the Hardware Authenticator doesn&amp;#39;t ship to the UK&lt;/small&gt;&lt;/p&gt;

&lt;h2 id=&quot;totp-vs-hotp&quot;&gt;TOTP vs HOTP&lt;/h2&gt;

&lt;p&gt;The codes generated by the Symantec VIP Access phone app (and the likes of Google Authenticator) are &lt;a href=&quot;https://en.wikipedia.org/wiki/Time-based_One-time_Password_algorithm&quot;&gt;TOTP codes&lt;/a&gt; - the code depends on the time. The other option is &lt;a href=&quot;https://en.wikipedia.org/wiki/HMAC-based_One-time_Password_algorithm&quot;&gt;HOTP&lt;/a&gt; which uses a counter instead - this is what the &lt;a href=&quot;https://www.amazon.com/dp/B07YGYLY9D&quot;&gt;Symantec VIP Hardware Authenticator&lt;/a&gt; does, and simplifies things on devices like the Yubikey that don&amp;#39;t have built-in clocks.&lt;/p&gt;

&lt;p&gt;Here are the main differences:&lt;/p&gt;

&lt;table style=&quot;width:100%&quot;&gt;
  &lt;tr&gt;
    &lt;th&gt;TOTP&lt;/th&gt;
    &lt;th&gt;HOTP&lt;/th&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;ul&gt;
      &lt;li&gt;Based on time - new code every 30 seconds&lt;/li&gt;
      &lt;li&gt;Requires a program on your computer - cannot use Yubikey's keyboard emulation&lt;/li&gt;
      &lt;li&gt;Can be backed up at creation time&lt;/li&gt;
    &lt;/ul&gt;&lt;/td&gt;
    &lt;td&gt;&lt;ul&gt;
      &lt;li&gt;Based on counter - new code every button press&lt;/li&gt;
      &lt;li&gt;Yubikey keyboard emulation works - no software needed&lt;/li&gt;
      &lt;li&gt;More difficult to back up, as counter changes on every code use&lt;/li&gt;
    &lt;/ul&gt;&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;

&lt;h2 id=&quot;if-you-choose-totp&quot;&gt;If you choose TOTP&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Install &lt;a href=&quot;https://github.com/dlenski/python-vipaccess&quot;&gt;python-vipaccess&lt;/a&gt; with &lt;code&gt;pip3 install python-vipaccess&lt;/code&gt; and &lt;a href=&quot;https://developers.yubico.com/yubioath-desktop/&quot;&gt;yubioath&lt;/a&gt; with &lt;code&gt;sudo apt-get install yubioath-desktop&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Execute python-vipaccess from wherever pip installed it (in my case &lt;code&gt;~/.local/bin/vipaccess&lt;/code&gt;) like so:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;
$ ~/.local/bin/vipaccess provision -p
Generating request...
Fetching provisioning response...
Getting token from response...
Decrypting token...
Checking token...
Credential created successfully:
    otpauth://totp/VIP%20Access:&lt;span class=&quot;tokenId&quot;&gt;VSST89795985&lt;/span&gt;?secret=&lt;span class=&quot;secret&quot;&gt;KVIMXW236KKUVMSVNYKZOBFPTWMKMPKZ&lt;/span&gt;&amp;digits=6&amp;algorithm=SHA1&amp;issuer=Symantec&amp;period=30
This credential expires on this date: 2023-03-29T16:24:42.226Z

You will need the ID to register this credential: VSST89795985

You can use oathtool to generate the same OTP codes
as would be produced by the official VIP Access apps:

    oathtool    -b --totp KVIMXW236KKUVMSVNYKZOBFPTWMKMPKZ  # output one code
    oathtool -v -b --totp KVIMXW236KKUVMSVNYKZOBFPTWMKMPKZ  # ... with extra information
&lt;/pre&gt;

&lt;p&gt;This gives you the TOTP secret and token ID. If you want to back up the credential or also load it into a tool like Google Authenticator, now is the time; to generate a QR code, see the &lt;a href=&quot;https://github.com/dlenski/python-vipaccess/blob/master/README.md#display-a-qr-code-to-register-your-credential-with-mobile-totp-apps&quot;&gt;python-vipaccess README&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Then simply load the secret onto your Yubikey and test as follows:&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;
$ read -p &quot;Enter the secret: &quot; totpsecret
Enter the secret: &lt;span class=&quot;secret&quot;&gt;KVIMXW236KKUVMSVNYKZOBFPTWMKMPKZ&lt;/span&gt;

$ yubioath put --name &lt;span class=&quot;tokenId&quot;&gt;VSST89795985&lt;/span&gt; --oath-type totp --touch &quot;$totpsecret&quot;

$ yubioath
&lt;span class=&quot;tokenId&quot;&gt;VSST89795985&lt;/span&gt;  [Touch credential]

$ yubioath show &lt;span class=&quot;tokenId&quot;&gt;VSST89795985&lt;/span&gt;
Touch your YubiKey...
VSST89795985      857363

$ unset totpsecret
&lt;/pre&gt;

&lt;p&gt;We use &lt;code&gt;read&lt;/code&gt; above to avoid saving the secret into our bash history. You can also use &lt;code&gt;yubioath-gui&lt;/code&gt; if you prefer a GUI.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Test your token at &lt;a href=&quot;https://vip.symantec.com/otpCheck&quot;&gt;Symantec&amp;#39;s website&lt;/a&gt; to confirm you&amp;#39;ve set it up right.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;calling-yubioath-from-python&quot;&gt;Calling yubioath from python&lt;/h3&gt;

&lt;p&gt;If you&amp;#39;ve got a python script to log into something, and you want to call yubioath from it, you can do it like so:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;#!/usr/bin/env python3
import subprocess

keyId = &amp;quot;VSST89795985&amp;quot;
pintoken = &amp;#39;&amp;#39;

while pintoken == &amp;#39;&amp;#39;:
    ykResult = subprocess.run([&amp;quot;yubioath&amp;quot;, &amp;quot;show&amp;quot;, keyId], stdout=subprocess.PIPE)
    if ykResult.returncode == 0:
        pintoken = str(ykResult.stdout, &amp;#39;utf-8&amp;#39;).split()[-1]
    else:
        pintoken = input(&amp;#39;Enter token manually, or press enter to retry yubikey: &amp;#39;)

print(&amp;quot;Token:&amp;quot;, pintoken)
&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The &lt;code&gt;while&lt;/code&gt; loop ensures, if the code ran yubioath stage before you put your key in, you can put it in and try again.&lt;/p&gt;

&lt;h2 id=&quot;if-you-choose-hotp&quot;&gt;If you choose HOTP&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Install &lt;a href=&quot;https://github.com/dlenski/python-vipaccess&quot;&gt;python-vipaccess&lt;/a&gt; with &lt;code&gt;pip3 install python-vipaccess&lt;/code&gt; and &lt;a href=&quot;https://developers.yubico.com/yubikey-manager-qt/&quot;&gt;Yubikey Manager&lt;/a&gt; with &lt;code&gt;sudo apt-add-repository ppa:yubico/stable &amp;amp;&amp;amp; sudo apt update &amp;amp;&amp;amp; sudo apt install yubikey-manager-qt&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Execute python-vipaccess from wherever pip installed it (in my case &lt;code&gt;~/.local/bin/vipaccess&lt;/code&gt;) like so:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;
$ ~/.local/bin/vipaccess provision -p -t FT12
Generating request...
Fetching provisioning response...
Getting token from response...
Decrypting token...
Checking token...
Credential created successfully:
    otpauth://hotp/VIP%20Access:&lt;span class=&quot;tid2&quot;&gt;FT1263782685&lt;/span&gt;?secret=&lt;span class=&quot;sec2&quot;&gt;KXVJPCQHMKLRP5FOPBW43OTV2424CXVY&lt;/span&gt;&amp;digits=6&amp;algorithm=SHA1&amp;issuer=Symantec&amp;counter=2
This credential expires on this date: 2023-03-29T18:00:44.119Z

You will need the ID to register this credential: FT1263782685
&lt;/pre&gt;

&lt;p&gt;The prefix comes from &lt;a href=&quot;https://knowledge.broadcom.com/external/article?legacyId=tech239895&quot;&gt;Symantec&amp;#39;s list of prefixes&lt;/a&gt; listed as &amp;#39;event based&amp;#39; - Prefixes like UBHE also work.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Remember to note down the ID - &lt;span class=&quot;tid2&quot;&gt;FT1263782685&lt;/span&gt; in the example above - as you&amp;#39;ll need it to make use of your new credential.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Yubikey&amp;#39;s keyboard-emulation has two &amp;#39;slots&amp;#39; - Slot 1 is triggered by a short press, and comes factory-configured for &lt;a href=&quot;https://developers.yubico.com/OTP/&quot;&gt;Yubico OTP&lt;/a&gt;. Slot 2 is triggered by a long press, and from the factory is empty; below, we confirm slot 2 is empty and load our credential into that slot. &lt;strong&gt;If a slot isn&amp;#39;t empty, don&amp;#39;t overwrite it unless you&amp;#39;re happy to lose whatever credential is in that slot&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;
$ ykman otp info
Slot 1: programmed
Slot 2: empty

$ read -p &quot;Enter the secret: &quot; hotpsecret
Enter the secret: &lt;span class=&quot;sec2&quot;&gt;KXVJPCQHMKLRP5FOPBW43OTV2424CXVY&lt;/span&gt;

$ ykman otp --counter 2 hotp 2 &quot;$hotpsecret&quot;
Program a HOTP credential in slot 2? [y/N]: y

$ unset hotpsecret
&lt;/pre&gt;

&lt;p&gt;You can use &lt;code&gt;ykman-gui&lt;/code&gt; to do the same thing with a GUI, if you prefer.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Now when you long-press (short press if you used slot 1) your Yubikey will emulate a keyboard entering a 6-digit code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Test your token at &lt;a href=&quot;https://vip.symantec.com/otpCheck&quot;&gt;Symantec&amp;#39;s website&lt;/a&gt; to confirm you&amp;#39;ve set it up right.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/prism.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/components/prism-python.min.js&quot;&gt;&lt;/script&gt;
</content>
 </entry>
 
 <entry>
   <title>How cheap digital verniers work</title>
   <link href="https://www.mjt.me.uk/posts/digital-vernier-teardown/"/>
   <updated>2017-04-01T00:00:00+01:00</updated>
   <id>https://www.mjt.me.uk/posts/digital-vernier-teardown</id>
   <content type="html">&lt;p&gt;Ever wondered how cheap digital verniers are able to produce good precision at very low prices? I did, so I took one apart.&lt;/p&gt;

&lt;p&gt;I&amp;#39;m not the first person to look at this - &lt;a href=&quot;http://www.grant-trebbin.com/2014/04/digital-calliper-teardown-and-repair.html&quot;&gt;Grant Trebbin has some photos of a teardown&lt;/a&gt;, and has done a good job of finding patents like &lt;a href=&quot;https://www.google.com/patents/US5068653&quot;&gt;US5068653 Capacitive displacement measuring device with t-shaped scale coatings&lt;/a&gt;; &lt;a href=&quot;https://web.archive.org/web/20130615164813/http://www.yadro.de/digital-scale/working.html&quot;&gt;Nick Müller has inspected one with an oscilliscope&lt;/a&gt; and &lt;a href=&quot;http://glanyi.en.made-in-china.com/custom-detail/xJQxmEnAMEhQQQmxJxnKeEdE/How-does-the-Electronic-Module-Work-.html&quot;&gt;Anyi Instrument Co&lt;/a&gt; have posted some info on how the sensors work.&lt;/p&gt;

&lt;p&gt;Turns out they use capacitive sensing - there&amp;#39;s a thin PCB hidden under a label on the shaft of the vernier:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/vernier/capacitive-sensor-600dpi.jpg&quot; alt=&quot;Capacitive sensing elements&quot;&gt;&lt;/p&gt;

&lt;p&gt;The green PCB on the left is for the slider. Every eighth bar in the densely striped section is connected together - i.e. the first, 9th and 17th bars are connected together, as are the 2nd, 10th and 18th, and so on.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/vernier/sensor-transparent-overlay-cropped.jpg&quot; alt=&quot;Slider overlaid on shaft&quot;&gt;&lt;/p&gt;

&lt;p&gt;I measured the distance between the PCBs on the slider and shaft using a cheap feeler gauge; the spacing was about 0.35mm ±0.05mm.&lt;/p&gt;

&lt;p&gt;Based on the 600 dpi scan above, the T sections on the shaft and the densely striped section is about 250 mm², and each of the eight banks of stripes has an area of 31 mm². The return strip has an area of about 95 mm². The comb overlaps the ground plane by about 43mm²; while that&amp;#39;s obviously the same order of magnitude as the return strip, they don&amp;#39;t seem to have been made precisely the same surface area.&lt;/p&gt;

&lt;p&gt;So each of the eight stripes has a capaitance of about &lt;a href=&quot;https://www.wolframalpha.com/input/?i=capacitance+of+parallel+plates&amp;amp;rawformassumption=%7B%22FS%22%7D+-%3E+%7B%7B%22ParallelPlateCapacitance%22,+%22C%22%7D%7D&amp;amp;rawformassumption=%7B%22F%22,+%22ParallelPlateCapacitance%22,+%22A%22%7D+-%3E%2231+mm%5E2%22&amp;amp;rawformassumption=%7B%22F%22,+%22ParallelPlateCapacitance%22,+%22d%22%7D+-%3E%220.35+mm%22&amp;amp;rawformassumption=%7B%22F%22,+%22ParallelPlateCapacitance%22,+%22er%22%7D+-%3E%221%22&quot;&gt;0.78 picofarads&lt;/a&gt; while the return strip has a capacitance of about &lt;a href=&quot;https://www.wolframalpha.com/input/?i=capacitance+of+parallel+plates&amp;amp;rawformassumption=%7B%22FS%22%7D+-%3E+%7B%7B%22ParallelPlateCapacitance%22,+%22C%22%7D%7D&amp;amp;rawformassumption=%7B%22F%22,+%22ParallelPlateCapacitance%22,+%22A%22%7D+-%3E%2295+mm%5E2%22&amp;amp;rawformassumption=%7B%22F%22,+%22ParallelPlateCapacitance%22,+%22d%22%7D+-%3E%220.35+mm%22&amp;amp;rawformassumption=%7B%22F%22,+%22ParallelPlateCapacitance%22,+%22er%22%7D+-%3E%221%22&quot;&gt;2.4 picofarads&lt;/a&gt; - taken in series, that&amp;#39;s about equivalent to 0.588 picofarads. That&amp;#39;s very small. For example, the ADC on an ATMega (like an Arduino Uno) has an input capacitance of ~14pF. It&amp;#39;s also smaller than the input capacitance of my oscilliscope. But some capacitive sensors claim to be able to measure femtofarad capacitance changes - the &lt;a href=&quot;http://www.analog.com/media/en/technical-documentation/data-sheets/AD7745_7746.pdf&quot;&gt;AD7745 claims an accuracy of 4 femtofarads&lt;/a&gt;, and &lt;a href=&quot;http://www.analog.com/media/en/technical-documentation/data-sheets/AD7147.pdf&quot;&gt;the AD7147 a sub-femtofarad output noise&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The stripes in the densely striped section are about 0.63mm wide, and the vernier&amp;#39;s precision is 0.01mm. That means, if my estimate of a 588 femtofarad capacitance is correct, the capacitance measurement is precise to about 9 femtofarads.&lt;/p&gt;

&lt;p&gt;If you attach an oscilliscope to the eight sets of bars in the striped section, and the return bar, here&amp;#39;s what you see:&lt;/p&gt;

&lt;!--
cat scope-01-seven-channels-a-is-output_1.csv | sed -n '1~2!p' | sed -n '1~2!p' | sed -n '1~2!p' | sed -n '1~2!p' &gt; decimated.csv
head -n 1 scope-01-seven-channels-a-is-output_1.csv &gt; short.csv
cat decimated.csv | awk -F, '{OFS=&quot;,&quot;;print $1,$2,$3,$4,$5,$6,$7,$8,$9,1.6-$6}' &gt;&gt; short.csv

head -n 1 scope-01-seven-channels-a-is-output_1.csv &gt; first5k.csv
tail -n +4 scope-01-seven-channels-a-is-output_1.csv | head -n 5000 | awk -F, '{OFS=&quot;,&quot;;print $1,$2,$3,$4,$5,$6,$7,$8,$9,1.6-$6}' &gt;&gt; first5k.csv
--&gt;

&lt;div style=&quot;width:100%; height:50vh; max-height:350px; position: relative;&quot;&gt;
    &lt;canvas id=&quot;chartCanvas1&quot; style=&quot;z-axis: 0; position: absolute; top: 0; left: 0;&quot;&gt;&lt;/canvas&gt;
    &lt;canvas id=&quot;crosshairCanvas1&quot; style=&quot;z-axis: 1; position: absolute; top: 0; left: 0;&quot;&gt;&lt;/canvas&gt;
    &lt;noscript&gt;
&lt;h1&gt;&lt;font color=&quot;red&quot;&gt;Hello, noscript users! A graph will appear here if you enable javascript for this site and cdnjs.cloudflare.com&lt;/font&gt;&lt;/h1&gt;
    &lt;/noscript&gt;
&lt;/div&gt;

&lt;p&gt;( &lt;a href=&quot;/assets/images/vernier/scope-01-seven-channels-a-is-output_1.csv.gz&quot;&gt;Raw data CSV&lt;/a&gt; )&lt;/p&gt;

&lt;p&gt;Of course, the oscilliscope&amp;#39;s probes introduce a certain extra resistance and capacitance. Several tens of picofarads of capacitance and 10 MOhms of resistance, both to ground, would be typical.&lt;/p&gt;

&lt;p&gt;Unfortunately, I didn&amp;#39;t keep track of exactly which channel was which - but Nick Müller&amp;#39;s oscilliscope work, linked above, shows us the inputs that are inversions of one another are four bars apart in the striped section. Also, as I used an 8-channel oscilliscope, I could only track the output and seven inputs. So the line marked &amp;quot;Input 5&amp;quot; is just input 6 flipped over.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s zoom in on that first section.&lt;/p&gt;

&lt;div style=&quot;width:100%; height:50vh; max-height:350px; position: relative;&quot;&gt;
    &lt;canvas id=&quot;chartCanvas2&quot; style=&quot;z-axis: 0; position: absolute; top: 0; left: 0;&quot;&gt;&lt;/canvas&gt;
    &lt;canvas id=&quot;crosshairCanvas2&quot; style=&quot;z-axis: 1; position: absolute; top: 0; left: 0;&quot;&gt;&lt;/canvas&gt;
    &lt;noscript&gt;
&lt;h1&gt;&lt;font color=&quot;red&quot;&gt;Hello, noscript users! A graph will appear here if you enable javascript for this site and cdnjs.cloudflare.com&lt;/font&gt;&lt;/h1&gt;
    &lt;/noscript&gt;
&lt;/div&gt;

&lt;p&gt;Nick Müller&amp;#39;s trace shows the output spiking high and low in equal amounts - I assume the fact mine doesn&amp;#39;t is because it&amp;#39;s clamped to the battery voltage by a diode, or something similar. The low spikes have a width of about 0.01ms - presumably something pulls the output to the center value after the spike has been measured.&lt;/p&gt;

&lt;p&gt;The sensing cycle appears to take differential measurements between of bars; in the diagram above a pair of lines either becomes narrow or becomes wide. The sensing cycle appears to rotate between all channels narrowing (widening); three of the four channels widening (narrowing) while the remaining channel is fixed; and three of the four channels widening (narrowing) while the remaining channel does the opposite.&lt;/p&gt;

&lt;p&gt;A complete sensing cycle takes around 1.7 milliseconds - although the system may average multiple sensing cycles to reduce noise. The AD7147, linked above, takes 6-36ms to sample 8 inputs (depending on how precisely you want to measure).&lt;/p&gt;

&lt;p&gt;The comb on the vernier shaft has a tooth pitch of 5mm. In other words, if the slider instantly moved 5mm, it would be undetectable, or &amp;#39;ambiguous&amp;#39;. So what&amp;#39;s the top speed you could go at? Depends (a) how much sample averaging you need and (b) if you can measure while moving. Assuming you can measure while moving, if a measurement takes 1.7ms and you want four per ambiguity step (i.e. a measurement every 1.25mm) you could go as fast as 0.7 m/s - but if it takes 66ms to make such a measurement, your speed would drop to 0.035 m/s. Or maybe the measurements work some other way and I&amp;#39;m completely wrong!&lt;/p&gt;

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.2.2/Chart.bundle.min.js&quot; integrity=&quot;sha384-c+7NPPbG70lQWJE8uEteRnsD8xbXg2UbC1/haquKYVIhyo95y1GB7KuXmPby5oXF&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js&quot; integrity=&quot;sha384-CgeP3wqr9h5YanePjYLENwCTSSEz42NJkbFpAFgHWQz7u3Zk8D00752ScNpXqGjS&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;/assets/images/vernier/vernier.js&quot;&gt;&lt;/script&gt;
</content>
 </entry>
 
 <entry>
   <title>ESP8266 SPI Flash protocol</title>
   <link href="https://www.mjt.me.uk/posts/esp8266-spi-flash-protocol/"/>
   <updated>2016-09-19T00:00:00+01:00</updated>
   <id>https://www.mjt.me.uk/posts/esp8266-spi-flash-protocol</id>
   <content type="html">&lt;p&gt;I was wondering whether the ESP8266 SPI flash could be used for atomic (or sort-of-atomic) write operations - so I wanted to understand how the underlying SPI operations work.&lt;/p&gt;

&lt;h2 id=&quot;tldr&quot;&gt;TLDR&lt;/h2&gt;

&lt;table&gt;&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;API call&lt;/th&gt;
&lt;th&gt;SPI command&lt;/th&gt;
&lt;th&gt;Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spi_flash_erase_sector&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x20&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Repeated status reads (command &lt;code&gt;0x05&lt;/code&gt;) until erase completes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spi_flash_read&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0xBB&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Dual SPI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spi_flash_write&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x02&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Single status read, test completed immediately&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;Read on to learn more...&lt;/p&gt;

&lt;h2 id=&quot;some-of-the-different-spi-flash-chips-found-on-esp8266-modules&quot;&gt;Some of the different SPI flash chips found on ESP8266 modules&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The ESP-12F on my WeMos D1 Mini uses a &lt;a href=&quot;https://www.winbond.com/resource-files/w25q32bv_revi_100413_wo_automotive.pdf&quot;&gt;Winbond W25Q32BV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://www.sparkfun.com/products/13231&quot;&gt;SparkFun Thing&lt;/a&gt; uses an &lt;a href=&quot;http://www.adestotech.com/fileview/1474205632485976354DS-AT25SF041_044.pdf&quot;&gt;Adesto AT25SF041&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A black ESP-01 I brought on ebay uses a &lt;a href=&quot;http://www.chinan-sx.com/uploadfile/cfile/2010119111110143.pdf&quot;&gt;Berg Micro 25q80a&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These different chips seem to have enough commands in common that they can be substituted for one another.&lt;/p&gt;

&lt;h2 id=&quot;dual-and-quad-spi&quot;&gt;Dual and Quad SPI&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus&quot;&gt;Traditional SPI&lt;/a&gt; has &amp;#39;MOSI&amp;#39; and &amp;#39;MISO&amp;#39; lines, with data travelling in opposite directions. If you don&amp;#39;t know what MOSI and MISO mean, go review that wikipedia article otherwise the rest of this explanation won&amp;#39;t make much sense!&lt;/p&gt;

&lt;p&gt;The flash chips listed above support &amp;#39;Dual SPI&amp;#39; which basically means, instead of MOSI and MISO always going in opposite directions, certain commands cause both lines to temporarily be used in the same direction. Here&amp;#39;s an example:&lt;/p&gt;

&lt;div style=&quot;width:100%; height:50vh; max-height:350px; position: relative;&quot;&gt;
    &lt;canvas id=&quot;chartCanvas1&quot; style=&quot;z-axis: 0; position: absolute; top: 0; left: 0;&quot;&gt;&lt;/canvas&gt;
    &lt;canvas id=&quot;crosshairCanvas1&quot; style=&quot;z-axis: 1; position: absolute; top: 0; left: 0;&quot;&gt;&lt;/canvas&gt;
    &lt;noscript&gt;
&lt;h1&gt;&lt;font color=&quot;red&quot;&gt;Hello, noscript users! A graph will appear here if you enable javascript for this site and cdnjs.cloudflare.com&lt;/font&gt;&lt;/h1&gt;
    &lt;/noscript&gt;
&lt;/div&gt;

&lt;p&gt;The &lt;font color=&quot;#1eb6c7&quot;&gt;first byte on MOSI&lt;/font&gt; is &lt;code&gt;10111011&lt;/code&gt; or &lt;code&gt;0xBB&lt;/code&gt; in hex - what the Winbond datasheet calls &amp;quot;Fast Read Dual I/O&amp;quot;.&lt;/p&gt;

&lt;p&gt;When that command is received, MISO changes direction for 16 clock cycles, allowing the master to output &lt;font color=&quot;#9520d4&quot;&gt;24 bits of address data in 12 clock cycles&lt;/font&gt; followed by &lt;font color=&quot;#d42059&quot;&gt;8 bits of control options, sent in 4 clock cycles&lt;/font&gt;. You read the bytes MISO-MOSI-MISO-MOSI- so the address above is &lt;code&gt;001111111011000000000000&lt;/code&gt; or &lt;code&gt;0x3FB000&lt;/code&gt; and the control options are &lt;code&gt;0x00&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After this, MISO and MOSI change direction - &lt;font color=&quot;#ced420&quot;&gt;both lines are used by the slave to send data to the master&lt;/font&gt;. In the example above, the data returned by the slave is all ones, or &lt;code&gt;0xFFFFFFFF&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quad SPI&lt;/strong&gt; adds an extra two lines between master and slave, and allowing for the transfer of four bits per clock cycle. When the Arduino IDE offers the choice between flash modes &amp;#39;DIO&amp;#39; and &amp;#39;QIO&amp;#39; flash this is what you&amp;#39;re choosing between (whether you&amp;#39;ll have the choice depends on the board you have selected).&lt;/p&gt;

&lt;p&gt;The practical speed benefits of Quad SPI over Dual SPI seem suprisingly modest, according to &lt;a href=&quot;http://www.esp8266.com/viewtopic.php?f=8&amp;amp;t=10377&quot;&gt;speed test results reported on esp8266.com&lt;/a&gt; which reports read times reducing by only 14% when changing from dual to quad SPI.&lt;/p&gt;

&lt;h2 id=&quot;programs-execute-from-spi-flash&quot;&gt;Programs execute from SPI flash&lt;/h2&gt;

&lt;p&gt;As you may know, user programs can be up to a megabyte, but there are only 64 kilobytes of instruction memory. This means quite a lot of data gets shuttled over the SPI bus under normal operation. &lt;/p&gt;

&lt;p&gt;I haven&amp;#39;t looked into the details, but I assume the ESP8266 does some sort of multitasking, so it can look after all the wifi maintainance stuff in the background while the user&amp;#39;s program runs. Anyway, in my tests I found that even when I put a long delay in my program, the SPI bus wasn&amp;#39;t always silent during that time.&lt;/p&gt;

&lt;h2 id=&quot;how-i-tested-the-spi-behaviour&quot;&gt;How I tested the SPI behaviour&lt;/h2&gt;

&lt;p&gt;Initially, I tried to use a 1.5MHz bandwidth two-channel scope to record MOSI and MISO, inferring the clock transitions from changes in the data lines. This didn&amp;#39;t work very well, because you can&amp;#39;t capture a 40MHz bus with a 1.5MHz scope; and if you slow the bus down far enough that you &lt;em&gt;can&lt;/em&gt; capture it your program will keep resetting with watchdog timer failures; and even if you ignore those you&amp;#39;ll most likely get a recording of code being loaded, as there&amp;#39;s a lot of that going on over the bus.&lt;/p&gt;

&lt;p&gt;So I moved to a 20MHz bandwidth 8-channel scope. This allowed me to also capture clock, chip select, and a pin I configured to act as a trigger when my test started.&lt;/p&gt;

&lt;p&gt;I used an ESP-12F on a breakout board that exposes all pins (including the SPI flash pins)&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s the program I used:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clike&quot; data-lang=&quot;clike&quot;&gt;extern &amp;quot;C&amp;quot; {
#include &amp;quot;spi_flash.h&amp;quot; // Provides SPI_FLASH_SEC_SIZE (usually 4096)
}

extern &amp;quot;C&amp;quot; uint32_t _SPIFFS_end; // Usually points to 0x405FB000
const uint32_t START_ADDRESS_BYTES = (uint32_t)&amp;amp;_SPIFFS_end - 0x40200000;
const uint32_t START_ADDRESS_FLASH_SECTORS = START_ADDRESS_BYTES/SPI_FLASH_SEC_SIZE;

const int led = 2;
const int LED_ON = LOW;
const int LED_OFF = HIGH;

void setup() {
  pinMode(led, OUTPUT);
  digitalWrite(led, LED_OFF);
  Serial.begin(115200);
  Serial.println(&amp;quot;Started.&amp;quot;);
}

void loop() {
  delay(500);
  Serial.println(&amp;quot;Testing SPI flash...&amp;quot;);

  noInterrupts();
  digitalWrite(led, LED_ON); // We can trigger our scope on this.

  // Reduce SPI clock speed so it fits in our scope&amp;#39;s bandwidth
  uint32_t clkbefore = SPI0CLK;
  SPI0CLK = 0x00D43002;

  spi_flash_erase_sector(START_ADDRESS_FLASH_SECTORS);
  uint32_t readBuf[1] = {0};
  spi_flash_read(START_ADDRESS_BYTES, readBuf, sizeof(readBuf));
  uint32_t writeBuf[1] = {0xF0F0F0F0};
  spi_flash_write(START_ADDRESS_BYTES, writeBuf, sizeof(writeBuf));

  SPI0CLK = clkbefore; // Restore SPI clock speed.
  digitalWrite(led, LED_OFF);
  interrupts();
}
&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;results&quot;&gt;Results&lt;/h2&gt;

&lt;h4 id=&quot;sector-erase&quot;&gt;Sector erase&lt;/h4&gt;

&lt;div style=&quot;width:100%; height:50vh; max-height:350px; position: relative;&quot;&gt;
    &lt;canvas id=&quot;chartCanvas2&quot; style=&quot;z-axis: 0; position: absolute; top: 0; left: 0;&quot;&gt;&lt;/canvas&gt;
    &lt;canvas id=&quot;crosshairCanvas2&quot; style=&quot;z-axis: 1; position: absolute; top: 0; left: 0;&quot;&gt;&lt;/canvas&gt;
    &lt;noscript&gt;
&lt;h1&gt;&lt;font color=&quot;red&quot;&gt;Hello, noscript users! Another graph here.&lt;/font&gt;&lt;/h1&gt;
    &lt;/noscript&gt;
&lt;/div&gt;

&lt;p&gt;&lt;code&gt;spi_flash_erase_sector&lt;/code&gt; is called to erase sector &lt;code&gt;0x3FB&lt;/code&gt;, producing the command &lt;font color=&quot;#1eb6c7&quot;&gt;20&lt;/font&gt; &lt;font color=&quot;#9520d4&quot;&gt;3F B0 00&lt;/font&gt; on MOSI then repeated status checks (MOSI &lt;font color=&quot;#d42059&quot;&gt;05&lt;/font&gt; 00, MISO FF &lt;font color=&quot;#ced420&quot;&gt;02&lt;/font&gt; and &lt;code&gt;FF 03&lt;/code&gt;) until the status reports the operation is complete (MISO &lt;code&gt;FF 00&lt;/code&gt;)&lt;/p&gt;

&lt;h4 id=&quot;data-read&quot;&gt;Data read&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;spi_flash_read&lt;/code&gt; is called to read 32 bits from start of that sector - address &lt;code&gt;0x3FB000&lt;/code&gt;. The scope capture is shown in the &amp;#39;Dual SPI&amp;#39; section, as the read is performed with Dual SPI; &lt;code&gt;BB 74 00 FF FF&lt;/code&gt; on MOSI and &lt;code&gt;00 7C 00 FF FF&lt;/code&gt; on MISO. A read of &lt;code&gt;0xFFFFFFFF&lt;/code&gt; is the expected result for NAND flash that has just been erased.&lt;/p&gt;

&lt;h4 id=&quot;data-write&quot;&gt;Data write&lt;/h4&gt;

&lt;div style=&quot;width:100%; height:50vh; max-height:350px; position: relative;&quot;&gt;
    &lt;canvas id=&quot;chartCanvas3&quot; style=&quot;z-axis: 0; position: absolute; top: 0; left: 0;&quot;&gt;&lt;/canvas&gt;
    &lt;canvas id=&quot;crosshairCanvas3&quot; style=&quot;z-axis: 1; position: absolute; top: 0; left: 0;&quot;&gt;&lt;/canvas&gt;
    &lt;noscript&gt;
&lt;h1&gt;&lt;font color=&quot;red&quot;&gt;There'd be a third graph here, if you'd turned on javascript :)&lt;/font&gt;&lt;/h1&gt;
    &lt;/noscript&gt;
&lt;/div&gt;

&lt;p&gt;&lt;code&gt;spi_flash_write&lt;/code&gt; is called to write 32 bits to the same address; this produced &lt;font color=&quot;#1eb6c7&quot;&gt;02&lt;/font&gt; &lt;font color=&quot;#9520d4&quot;&gt;3F B0 00&lt;/font&gt; &lt;font color=&quot;#d42059&quot;&gt;F0 F0 F0 F0&lt;/font&gt; on MOSI and &lt;code&gt;00 00 00 00 00 00 00 00&lt;/code&gt; on MOSI, indicating that dual SPI was not used. Look how many clock cycles there are compared to the write! A status check (MOSI &lt;font color=&quot;#1eb6c7&quot;&gt;05&lt;/font&gt; 00 MISO 00 &lt;font color=&quot;#ced420&quot;&gt;00&lt;/font&gt;) returned immediately.&lt;/p&gt;

&lt;h2 id=&quot;raw-scope-capture&quot;&gt;Raw scope capture&lt;/h2&gt;

&lt;p&gt;Want to look at the data yourself in more detail? You can &lt;a href=&quot;/assets/images/spi-flash/spi-5channel-full.csv.gz&quot;&gt;download it as a 15 megabyte, 2 million row CSV&lt;/a&gt; - but you won&amp;#39;t be able to load it in Excel because it&amp;#39;s too big.&lt;/p&gt;

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/prism.js&quot; integrity=&quot;sha384-UsGFqgJJAl8uAk2o7M3fDA0fC1j2lTZBZDWJtERJkb34nTXL81ajYf1NE47ItiPH&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.2.2/Chart.bundle.min.js&quot; integrity=&quot;sha384-c+7NPPbG70lQWJE8uEteRnsD8xbXg2UbC1/haquKYVIhyo95y1GB7KuXmPby5oXF&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js&quot; integrity=&quot;sha384-CgeP3wqr9h5YanePjYLENwCTSSEz42NJkbFpAFgHWQz7u3Zk8D00752ScNpXqGjS&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;/assets/images/spi-flash/spi-flash.js&quot;&gt;&lt;/script&gt;
</content>
 </entry>
 
 <entry>
   <title>Picoscope's 1,048,579 line CSV limit</title>
   <link href="https://www.mjt.me.uk/posts/picoscope-csv-size-limits/"/>
   <updated>2016-09-18T00:00:00+01:00</updated>
   <id>https://www.mjt.me.uk/posts/picoscope-csv-size-limits</id>
   <content type="html">&lt;p&gt;If you&amp;#39;ve got here from Google, it&amp;#39;s probably because you&amp;#39;ve exported a CSV or TXT file from picoscope and it&amp;#39;s come out with 1048579 lines - maybe 3 of which are headers and 1048576 are data. You can &lt;a href=&quot;https://www.picotech.com/support/topic7095.html&quot;&gt;find&lt;/a&gt; &lt;a href=&quot;https://www.picotech.com/support/topic7607.html&quot;&gt;several&lt;/a&gt; &lt;a href=&quot;https://www.picotech.com/support/topic13903.html&quot;&gt;posts&lt;/a&gt; on their forum about the same thing.&lt;/p&gt;

&lt;p&gt;Seems like &lt;a href=&quot;https://support.office.com/en-gb/article/Excel-specifications-and-limits-1672b34d-7043-467e-8e27-269d656771c3&quot;&gt;Excel worksheets are limited to 1,048,576 rows by 16,384 columns&lt;/a&gt;, and Picoscope silently truncates CSVs to that length. I&amp;#39;m not sure why they decided to truncate silently, rather than giving the user the option to decimate the data or choose a window to export, or putting a note on the last line of the data saying that it had been truncated and why.&lt;/p&gt;

&lt;p&gt;Picoscope support recommends exporting in Matlab format instead. But what if you really want a big CSV, and you don&amp;#39;t have Matlab because it costs £1,600 a seat which is a lot of money for a single CSV? Python to the rescue!&lt;/p&gt;

&lt;h2 id=&quot;converting-picoscope-output-from-mat-to-csv&quot;&gt;Converting picoscope output from .mat to .csv&lt;/h2&gt;

&lt;p&gt;Here&amp;#39;s the Python script I used to do the conversion. My install of Ubuntu 16.04 already had Python 2.7.12 installed, but I had to run &lt;code&gt;sudo apt-get install python-scipy&lt;/code&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;import scipy.io
import numpy
mat = scipy.io.loadmat(&amp;#39;20160918-0002.mat&amp;#39;)
startTime = mat[&amp;#39;Tstart&amp;#39;][0][0]
numSamples = mat[&amp;#39;Length&amp;#39;][0][0]
endTime = startTime+numSamples*mat[&amp;#39;Tinterval&amp;#39;][0][0]
times = numpy.linspace(startTime, endTime, numSamples).reshape(numSamples,1)
arrayForCsv = numpy.concatenate((times, mat[&amp;#39;A&amp;#39;], mat[&amp;#39;B&amp;#39;], mat[&amp;#39;C&amp;#39;], mat[&amp;#39;D&amp;#39;], mat[&amp;#39;E&amp;#39;]), axis=1)
numpy.savetxt(&amp;#39;20160918-0002.csv.gz&amp;#39;, arrayForCsv, delimiter=&amp;#39;,&amp;#39;, fmt=&amp;#39;%.9f&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Note that you&amp;#39;ll have to change the &lt;code&gt;loadmat&lt;/code&gt; and &lt;code&gt;savetxt&lt;/code&gt; lines with the filenames you want, and change the &lt;code&gt;concatenate&lt;/code&gt; line if you weren&amp;#39;t using five channels. Simply change the &lt;code&gt;mat[&amp;#39;A&amp;#39;], mat[&amp;#39;B&amp;#39;]...mat[&amp;#39;E&amp;#39;]&lt;/code&gt; section to list the channels you want in your CSV.&lt;/p&gt;

&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/prism.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/components/prism-python.min.js&quot;&gt;&lt;/script&gt;
</content>
 </entry>
 
 <entry>
   <title>ESP8266 GPIO on deep sleep and reset</title>
   <link href="https://www.mjt.me.uk/posts/esp8266-gpio-deep-sleep-and-reset/"/>
   <updated>2016-08-09T00:00:00+01:00</updated>
   <id>https://www.mjt.me.uk/posts/esp8266-gpio-deep-sleep-and-reset</id>
   <content type="html">&lt;p&gt;I want to do some battery powered sensing with an esp8266 - and to get a good battery life, I need to use the &amp;#39;deep sleep&amp;#39; mode. Deep sleep requires a reset (including a bootloader and some radio calibration) to wake from. I decided to test how different pins behave when in deep sleep or undergoing a reset.&lt;/p&gt;

&lt;h2 id=&quot;schematic&quot;&gt;Schematic&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/esp8266-reset/schematic.png&quot; alt=&quot;Schematic&quot;&gt;&lt;/p&gt;

&lt;p&gt;By switching the Arduino Uno outputs between high, low and high impedance, we can test a variety of pull up and pull down values applied to the pins of the module.&lt;/p&gt;

&lt;h3 id=&quot;notes&quot;&gt;Notes&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;These tests were performed on a &amp;#39;WeMos D1 Mini V2&amp;#39; module carrying an &amp;#39;ESP-12F&amp;#39; module carrying the esp8266. The modules include some pull and and down components. I&amp;#39;ve tried to note these below.&lt;/li&gt;
&lt;li&gt;As the picoscope has a 1 MΩ input impedance, a 100 kΩ pull up to 3.3v with no other load makes a resistor divider with a 3v output voltage.&lt;/li&gt;
&lt;li&gt;The timebase for the charts below is 100 milliseconds per division, and the vertical scale is in volts. The blue line is the reset signal and the red line is the pin being tested.&lt;/li&gt;
&lt;li&gt;The gap between &amp;#39;Reset pulled low&amp;#39; and &amp;#39;Chip restarting&amp;#39; is intentional, I put it in because of the GPIO0/GPIO2 bootloader behaviour (you&amp;#39;ll see it when you scroll down).&lt;/li&gt;
&lt;li&gt;The two test programs are at the end of this post. I programmed the esp8266 using Arduino board support package 2.3.0 - as some of the behaviour is probably bootloader/SDK dependent, YMMV.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;stimulus-circuit-output-without-esp8266&quot;&gt;Stimulus circuit output without ESP8266&lt;/h3&gt;

&lt;style&gt;
#scrollheader {
  position: fixed;
  top: 0px;
  left: 50%;
  transform: translate(-50%, 0)
}
&lt;/style&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/esp8266-reset/thin-header.png&quot; alt=&quot;Header&quot; id=&quot;fixedheader&quot;&gt;
&lt;img src=&quot;/assets/images/esp8266-reset/thin-header.png&quot; alt=&quot;Header&quot; id=&quot;scrollheader&quot;&gt;&lt;/p&gt;

&lt;script&gt;
window.onscroll = function() {headerStickyWhenScrolledPast()};
window.onload = function() {headerStickyWhenScrolledPast()};

function headerStickyWhenScrolledPast() {
    var fixedImagePosition = document.getElementById(&quot;fixedheader&quot;).getBoundingClientRect();
    //console.log(&quot;Top:&quot; + fixedImagePosition.top)
    if (fixedImagePosition.top &lt; 0) {
        document.getElementById(&quot;scrollheader&quot;).style.visibility = &quot;visible&quot;;
    } else {
        document.getElementById(&quot;scrollheader&quot;).style.visibility = &quot;hidden&quot;;
    }
}
&lt;/script&gt;

&lt;!-- Images cropped from bmp like: convert D0.bmp -crop 1440x305+20+155 c-D0.png; --&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/esp8266-reset/c-no-connection.png&quot; alt=&quot;Stimulus&quot;&gt;&lt;/p&gt;

&lt;h3 id=&quot;wemos-mini-pin-d0-gpio16&quot;&gt;WeMos mini pin D0 / GPIO16&lt;/h3&gt;

&lt;p&gt;Special function - timer reset when in deep sleep
&lt;img src=&quot;/assets/images/esp8266-reset/c-D0-v2.png&quot; alt=&quot;D0&quot;&gt;&lt;/p&gt;

&lt;h3 id=&quot;wemos-mini-pin-d1-gpio5&quot;&gt;WeMos mini pin D1 / GPIO5&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/esp8266-reset/c-D1.png&quot; alt=&quot;D1&quot;&gt;&lt;/p&gt;

&lt;h3 id=&quot;wemos-mini-pin-d2-gpio4&quot;&gt;WeMos mini pin D2 / GPIO4&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/esp8266-reset/c-D2.png&quot; alt=&quot;D2&quot;&gt;&lt;/p&gt;

&lt;h3 id=&quot;wemos-mini-pin-d3-gpio0&quot;&gt;WeMos mini pin D3 / GPIO0&lt;/h3&gt;

&lt;p&gt;10k pullup on D1 mini schematic, and reset circuit connection to DTR/RTS/RST
&lt;img src=&quot;/assets/images/esp8266-reset/c-D3.png&quot; alt=&quot;D3&quot;&gt;&lt;/p&gt;

&lt;h3 id=&quot;wemos-mini-pin-d4-gpio2&quot;&gt;WeMos mini pin D4 / GPIO2&lt;/h3&gt;

&lt;p&gt;10k pullup on D1 mini schematic, blue LED &amp;amp; 470 ohm resistor on ESP-12F
&lt;img src=&quot;/assets/images/esp8266-reset/c-D4.png&quot; alt=&quot;D4&quot;&gt;&lt;/p&gt;

&lt;h3 id=&quot;wemos-mini-pin-d5-gpio14&quot;&gt;WeMos mini pin D5 / GPIO14&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/esp8266-reset/c-D5.png&quot; alt=&quot;D5&quot;&gt;&lt;/p&gt;

&lt;h3 id=&quot;wemos-mini-pin-d6-gpio12&quot;&gt;WeMos mini pin D6 / GPIO12&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/esp8266-reset/c-D6.png&quot; alt=&quot;D6&quot;&gt;&lt;/p&gt;

&lt;h3 id=&quot;wemos-mini-pin-d7-gpio13&quot;&gt;WeMos mini pin D7 / GPIO13&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/esp8266-reset/c-D7.png&quot; alt=&quot;D7&quot;&gt;&lt;/p&gt;

&lt;h3 id=&quot;wemos-mini-pin-d8-gpio15&quot;&gt;WeMos mini pin D8 / GPIO15&lt;/h3&gt;

&lt;p&gt;10k pulldown on D1 mini schematic
&lt;img src=&quot;/assets/images/esp8266-reset/c-D8.png&quot; alt=&quot;D8&quot;&gt;&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;It takes 300ms from the reset pin rising edge for the user&amp;#39;s program to start running (at least when deep sleep mode WAKE&lt;em&gt;RF&lt;/em&gt;DEFAULT is used)&lt;/p&gt;

&lt;p&gt;Pins&amp;#39; values while in deep sleep, reset, and during restart are unaffected by the value the pin was set to before deep sleep.&lt;/p&gt;

&lt;p&gt;Individual pins behave differently, and their behaviours are as follows:&lt;/p&gt;

&lt;style&gt;
table { margin-top: 10px; margin-bottom: 10px; }
table, th, td { padding: 5px; }
th, td { border: 2px solid black; }
&lt;/style&gt;

&lt;table&gt;&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;D1 mini pin&lt;/th&gt;
&lt;th&gt;GPIO&lt;/th&gt;
&lt;th&gt;Deep sleep&lt;/th&gt;
&lt;th&gt;Reset held low&lt;/th&gt;
&lt;th&gt;During restart&lt;/th&gt;
&lt;th&gt;Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;D0&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;strong high&lt;/td&gt;
&lt;td&gt;strong high&lt;/td&gt;
&lt;td&gt;strong high&lt;/td&gt;
&lt;td&gt;special role - wake from deep sleep&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D1&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;high impedance&lt;/td&gt;
&lt;td&gt;high impedance&lt;/td&gt;
&lt;td&gt;high impedance&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D2&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;high impedance&lt;/td&gt;
&lt;td&gt;high impedance&lt;/td&gt;
&lt;td&gt;high impedance&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D3&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;~500 ohm high?&lt;/td&gt;
&lt;td&gt;~875 ohm high?&lt;/td&gt;
&lt;td&gt;~500 ohm high?&lt;/td&gt;
&lt;td&gt;Pull up resistor &amp;amp; controls boot behaviour&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D4&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;~5k pull up&lt;/td&gt;
&lt;td&gt;~5k pull up&lt;/td&gt;
&lt;td&gt;~5k pull up&lt;/td&gt;
&lt;td&gt;Pull up resistor &amp;amp; blue LED&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D5&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;high impedance&lt;/td&gt;
&lt;td&gt;weak high&lt;/td&gt;
&lt;td&gt;weak high&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D6&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;high impedance&lt;/td&gt;
&lt;td&gt;weak high&lt;/td&gt;
&lt;td&gt;weak high&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D7&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;high impedance&lt;/td&gt;
&lt;td&gt;weak high&lt;/td&gt;
&lt;td&gt;weak high&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D8&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;high imp &amp;amp; 10k pull down&lt;/td&gt;
&lt;td&gt;weak high &amp;amp; 10k pull down&lt;/td&gt;
&lt;td&gt;strong low&lt;/td&gt;
&lt;td&gt;Pull down resistor&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

&lt;h2 id=&quot;program-for-uno-to-provide-timed-pull-up-pull-down&quot;&gt;Program for Uno to provide timed pull up / pull down&lt;/h2&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clike&quot; data-lang=&quot;clike&quot;&gt;const int led = 13;
const int reset = 7;
const int oneKohm = 6;
const int tenKohm = 5;
const int hundredKohm = 4;
const int HIGH_impedance = INPUT;

void setup() {
  // put your setup code here, to run once:
  pinMode(reset, OUTPUT);
  digitalWrite(reset, HIGH);
  pinMode(led, OUTPUT);
  digitalWrite(led, HIGH);
}

void loop() {
  digitalWrite(led, HIGH);
  digitalWrite(reset, HIGH);
  delay(5000);
  digitalWrite(led, LOW);

  cycleLoads();
  delay(20);
  digitalWrite(reset, LOW);
  delay(20);
  cycleLoads();
  delay(20);
  digitalWrite(reset, HIGH);
  delay(120);
  cycleLoads();

}

void cycleLoads() {
  pinMode(oneKohm, HIGH_impedance);
  pinMode(tenKohm, HIGH_impedance);
  pinMode(hundredKohm, HIGH_impedance);
  delay(20);

  cyclePinUpDown(oneKohm);
  cyclePinUpDown(tenKohm);
  cyclePinUpDown(hundredKohm);
}

void cyclePinUpDown(int pin) {
  pinMode(pin, OUTPUT);
  digitalWrite(pin, HIGH);
  delay(20);
  digitalWrite(pin, LOW);
  delay(20);
  pinMode(pin, HIGH_impedance);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;program-for-the-esp8266&quot;&gt;Program for the esp8266:&lt;/h2&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clike&quot; data-lang=&quot;clike&quot;&gt;#include &amp;lt;ESP8266WiFi.h&amp;gt;

void setup() {
  pinMode(0, OUTPUT);
  digitalWrite(0, 0);
  pinMode(2, OUTPUT);
  digitalWrite(2, 0);
  pinMode(4, OUTPUT);
  digitalWrite(4, 0);
  pinMode(5, OUTPUT);
  digitalWrite(5, 0);
  pinMode(12, OUTPUT);
  digitalWrite(12, 0);
  pinMode(13, OUTPUT);
  digitalWrite(13, 0);
  pinMode(14, OUTPUT);
  digitalWrite(14, 0);
  pinMode(15, OUTPUT);
  digitalWrite(15, 0);
  pinMode(16, OUTPUT);
  digitalWrite(16, 0);

  delay(1000);

  ESP.deepSleep(0, WAKE_RF_DEFAULT);
}

void loop() {

}

&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/prism.js&quot;&gt;&lt;/script&gt;
</content>
 </entry>
 
 <entry>
   <title>Getting prism.js to work with Jekyll from a CDN</title>
   <link href="https://www.mjt.me.uk/posts/syntax-highlighting-prism-cdn/"/>
   <updated>2016-07-16T00:00:00+01:00</updated>
   <id>https://www.mjt.me.uk/posts/syntax-highlighting-prism-cdn</id>
   <content type="html">&lt;p&gt;One option to syntax-highlight some code in a web page is &lt;a href=&quot;http://prismjs.com/&quot;&gt;prism.js&lt;/a&gt;. I use it in some posts on this blog.&lt;/p&gt;

&lt;p&gt;It&amp;#39;s fairly simple to set up - but there&amp;#39;s a trick to getting it to work from a CDN. When you download prism.js from the project website, a configuration tool lets you choose the languages you want included, then gives you a prism.js with only those languages included.&lt;/p&gt;

&lt;h1 id=&quot;importing-support-for-the-language-you-need&quot;&gt;Importing support for the language you need&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://cdnjs.com/libraries/prism&quot;&gt;The version on cdnjs&lt;/a&gt; doesn&amp;#39;t have a configuration tool - but rather than making a big file with all languages included, the base version includes a small set of languages, and other languages can be imported by including additional components.&lt;/p&gt;

&lt;p&gt;The base version includes support for javascript, css, &amp;#39;markup&amp;#39; (which works on HTML, XML, and XML-based things like SVG) and &amp;#39;c-like&amp;#39;.&lt;/p&gt;

&lt;p&gt;Languages that you haven&amp;#39;t imported support for will be left unstyled - as if prism.js wasn&amp;#39;t working at all. You have to explicitly import the language support files you need. As an example, here&amp;#39;s how to style a bash script with prism.js from cdnjs:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;//cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/themes/prism.min.css&amp;quot;&amp;gt;

page content goes here

&amp;lt;code class=&amp;quot;language-bash&amp;quot;&amp;gt;
#!/bin/bash
set -e # Exit on failure
# bash script here!
&amp;lt;/code&amp;gt;

&amp;lt;script src=&amp;quot;//cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/prism.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&amp;quot;//cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/components/prism-bash.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;getting-it-to-work-with-jekyll&quot;&gt;Getting it to work with Jekyll&lt;/h1&gt;

&lt;p&gt;Follow &lt;a href=&quot;https://stackoverflow.com/a/14162208/1367431&quot;&gt;this stackoverflow answer&lt;/a&gt; to adjust your post template to support extra_css, then include the required stylesheet in the YAML frontmatter:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;---
layout: post
title: &amp;quot;Getting prism.js to work with Jekyll from a CDN&amp;quot;
description: &amp;quot;&amp;quot;
category:
tags: [programming, javascript, syntax highlighting, prismjs]
extra_css:
  - //cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/themes/prism.min.css
---
&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Then just indicate any code blocks with triple-backticks:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;```bash
#!/bin/bash
set -e # Exit on failure
# bash script here!
```
&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;and the results should look like this:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;#!/bin/bash
set -e # Exit on failure
# bash script here!
&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Congratulations! You (probably) now have prism.js syntax highlighting.&lt;/p&gt;

&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/prism.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/components/prism-yaml.min.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/components/prism-bash.min.js&quot;&gt;&lt;/script&gt;
</content>
 </entry>
 
 <entry>
   <title>Making an ubuntu box that's only on in business hours</title>
   <link href="https://www.mjt.me.uk/posts/ubuntu-sleep-outside-business-hours/"/>
   <updated>2016-06-16T00:00:00+01:00</updated>
   <id>https://www.mjt.me.uk/posts/ubuntu-sleep-outside-business-hours</id>
   <content type="html">&lt;p&gt;So you&amp;#39;ve got an ubuntu box you want on during business hours, but you don&amp;#39;t need it on outside business hours. Maybe it&amp;#39;s a build server or something similar. Obviously, you could manually start it every morning - but you might be ill or go on holiday. Let&amp;#39;s automate it with wake-on-RTC! The instructions below are for Ubuntu 14.04.&lt;/p&gt;

&lt;p&gt;First of all, create this file at /root/weekday-restart.sh (I use &lt;code&gt;sudo pico /root/weekday-restart.sh&lt;/code&gt; but you can use any text editor you like!)&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;#!/bin/bash
set -e # Exit on failure

# For some reason, if wakealarm is already set it&amp;#39;s an error to set it
# to a new value - unless we first clear it by writing 0 to it.
echo 0 &amp;gt; /sys/class/rtc/rtc0/wakealarm

# 1=Monday, 7=Sunday
current_day_of_week=$( date &amp;#39;+%u&amp;#39; )

if [ &amp;quot;$current_day_of_week&amp;quot; -lt &amp;quot;5&amp;quot; ]; then
  sleep_for_days=1
else
  sleep_for_days=$((8-current_day_of_week))
fi

# This bit determines the time of day for the next boot:
next_boot_text=$( date &amp;#39;+%Y-%m-%dT08:50:00&amp;#39; -d &amp;quot;+$sleep_for_days days&amp;quot; )
next_boot_unix=$( date &amp;#39;+%s&amp;#39; --date=&amp;quot;$next_boot_text&amp;quot; )

echo &amp;quot;$next_boot_unix&amp;quot; &amp;gt; /sys/class/rtc/rtc0/wakealarm
cat /sys/class/rtc/rtc0/wakealarm
echo &amp;quot;Scheduled wake for $next_boot_text = $next_boot_unix&amp;quot;

# You can make a call to cronitor or healthchecks.io here if you like.
&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Then make it executable and edit root&amp;#39;s crontab:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;chmod u+x /root/weekday-restart.sh
sudo crontab -e
&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;And add the following lines:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-crontab&quot; data-lang=&quot;crontab&quot;&gt;# m  h      dom  mon  dow   command
0    10,17  *    *    *     /root/weekday-restart.sh &amp;gt; /root/last-restart.log 2&amp;gt;&amp;amp;1
0    20     *    *    *     pm-suspend
&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Scheduling the restart will log the results (and any errors) to /root/last-restart.log so if you have any trouble you can debug it easily.&lt;/p&gt;

&lt;p&gt;The pm-suspend line suspends the box at 20:00 but the wake-on-rtc will work just as well if you power off the box entirely. This can also give you a convenient chance to apply any updates - but &lt;a href=&quot;https://serverfault.com/a/644942/360370&quot;&gt;if you&amp;#39;re going to run apt-get, make sure your script sets the path&lt;/a&gt; so it works right under cron.&lt;/p&gt;

&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/prism.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/components/prism-bash.min.js&quot;&gt;&lt;/script&gt;
</content>
 </entry>
 
 <entry>
   <title>Certificate Transparency and the Certificate Authority Death Penalty</title>
   <link href="https://www.mjt.me.uk/posts/certificate-transparency/"/>
   <updated>2016-03-23T00:00:00+00:00</updated>
   <id>https://www.mjt.me.uk/posts/certificate-transparency</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Certificate_Transparency&quot;&gt;Certificate Transparency&lt;/a&gt; (CT) is a proposal that, when a certificate authority issues a certificate, they should log the details in a public, append-only log.&lt;/p&gt;

&lt;p&gt;This allows &lt;a href=&quot;http://arstechnica.com/security/2014/07/emergency-windows-update-revokes-dozens-of-bogus-google-yahoo-ssl-certificates/&quot;&gt;mis-issued&lt;/a&gt; &lt;a href=&quot;https://security.googleblog.com/2013/12/further-improving-digital-certificate.html&quot;&gt;certificates&lt;/a&gt; &lt;a href=&quot;https://blog.mozilla.org/security/2011/08/29/fraudulent-google-com-certificate/&quot;&gt;to&lt;/a&gt; &lt;a href=&quot;http://arstechnica.com/security/2015/03/google-warns-of-unauthorized-tls-certificates-trusted-by-almost-all-oses/&quot;&gt;be&lt;/a&gt; &lt;a href=&quot;https://www.comodo.com/Comodo-Fraud-Incident-2011-03-23.html&quot;&gt;spotted&lt;/a&gt; &lt;a href=&quot;http://krebsonsecurity.com/2013/01/turkish-registrar-enabled-phishers-to-spoof-google/&quot;&gt;by&lt;/a&gt; &lt;a href=&quot;https://technet.microsoft.com/library/security/ms01-017&quot;&gt;site&lt;/a&gt; &lt;a href=&quot;http://www.theregister.co.uk/2012/02/14/trustwave_analysis/&quot;&gt;owners&lt;/a&gt; - and hopefully revoked in short order. Browsers, when they know to expect a CT entry, can reject a certificate as fraudulent if the expected CT entry is missing.&lt;/p&gt;

&lt;p&gt;But CT will have two other interesting effects I haven&amp;#39;t heard mentioned in other public discussion.&lt;/p&gt;

&lt;h3 id=&quot;the-certificate-authority-death-penalty&quot;&gt;The Certificate Authority Death Penalty&lt;/h3&gt;

&lt;p&gt;Currently, no matter how badly a certificate authority messes up, it&amp;#39;s difficult for browsers and OSes to remove them from the trusted root certificate set because of the collateral damage when innocent sites become unavailable. This is particularly an issue with the larger CAs; in a 2010 report, &lt;a href=&quot;https://www.eff.org/files/defconssliverse.pdf&quot;&gt;21.8% of valid certificates - 300,224 out of 1,377,067 - were signed by the same GoDaddy certificate&lt;/a&gt; so that would be pretty hard for Mozilla or Google or Microsoft to drop.&lt;/p&gt;

&lt;p&gt;But there is a way browser vendors could kill a CA without such collateral damage - they can &amp;#39;grandfather in&amp;#39; a list of certificates that should remain trusted even after the CA becomes untrusted. A list of every certificate issued by that CA that hasn&amp;#39;t expired or been revoked.&lt;/p&gt;

&lt;p&gt;You&amp;#39;d imagine every CA would maintain such a list in-house - but if the CA has messed up and they know the browser vendors are about to put them out of business, they have no incentive to cooperate and every incentive to claim the family dog ate their customer database.&lt;/p&gt;

&lt;p&gt;By generating a public database of issued certificates forcing CAs to put all certificates into it, browser vendors gain leverage over certificate authorities because they can put the certificate authority out of business with much less collateral damage.&lt;/p&gt;

&lt;h3 id=&quot;that-sounds-bad-for-certificate-authorities-but-it-39-s-actually-good&quot;&gt;That sounds bad for Certificate Authorities, but it&amp;#39;s actually good&lt;/h3&gt;

&lt;p&gt;So why would certificate authorities support this, if it puts a gun to their heads?&lt;/p&gt;

&lt;p&gt;The first reason is because they actually care about security. They don&amp;#39;t want to mis-issue certificates, and they&amp;#39;d rather their mistakes be detected and rectified. With &lt;a href=&quot;https://www.eff.org/files/defconssliverse.pdf&quot;&gt;over 650 organisations&lt;/a&gt; that can issue certificates, detecting and getting rid of the cowboys is good for the industry&amp;#39;s reputation.&lt;/p&gt;

&lt;p&gt;The second reason is browser vendors can do it with or without them - if CAs don&amp;#39;t submit to CT logs, browsers can do it for them (at the cost of missing mailserver certificates and corporate intranet sites that are never accessed by modern browsers).&lt;/p&gt;

&lt;p&gt;But the most interesting reason is, by radically increasing the cost of signing a bad certificate, it makes it much less likely anyone will force them to sign bad certificates. Game theoretician and nobel laureate Thomas C. Schelling describes the reason, in &lt;a href=&quot;https://books.google.co.uk/books?id=pS1wCwAAQBAJ&amp;amp;lpg=PT182&amp;amp;ots=rFRgtpAdGk&amp;amp;dq=%22it%20was%20reported%20unofficially%20during%20the%20Korean%20War%20that%20when%22&amp;amp;pg=PT182#v=onepage&amp;amp;q=%22it%20was%20reported%20unofficially%20during%20the%20Korean%20War%20that%20when%22&amp;amp;f=false&quot;&gt;The Strategy Of Conflict&lt;/a&gt;:&lt;/p&gt;

&lt;style&gt;
blockquote { font-style: italic; }
&lt;/style&gt;

&lt;blockquote&gt;
&lt;p&gt;There is probably no single principle of game theory that epitomizes so strikingly the mixed-motive game as this principle that a worsening of some or even all of the potential outcomes for a particular player and an improvement in none of them may be distinctly - even dramatically - advantageous for the player so disadvantaged. [...] It was reported unofficially during the Korean War that when the Treasury Department blocked Communist Chinese financial assets, it also knowingly blocked some non-Communist assets as a means of immunizing the owners against extortionate threats against their relatives still in China.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In simple terms: If you make it impossible for you to do something, nobody will try to force you to do that thing.&lt;/p&gt;

&lt;p&gt;If a CA can issue a certificate for windowsupdate.microsoft.com and the only cost is some bad publicity and a slap on the wrist, an extortionist can threaten something medium-sized (like revaling the CEO&amp;#39;s affair) expecting the company to cave. But if the cost is that the CA goes out of business within a week, the company is in a much better position: nobody would expect them to cave to such a threat, so nobody will bother to make such a threat.&lt;/p&gt;

&lt;style&gt;
table { margin-bottom: 20px; }
table, th, td { padding: 5px; }
th, td { border: 1px solid black; }
&lt;/style&gt;

&lt;p&gt;&lt;strong&gt;Payoff matrix without CT:&lt;/strong&gt;&lt;/p&gt;

&lt;table&gt;&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Threat&lt;/th&gt;
&lt;th&gt;Issues bad cert&lt;/th&gt;
&lt;th&gt;Doesn&amp;#39;t&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Request&lt;/td&gt;
&lt;td&gt;-10&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extortion&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;-10&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;-1000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bribery&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;990&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;Payoff matrix with CT:&lt;/strong&gt;&lt;/p&gt;

&lt;table&gt;&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Threat&lt;/th&gt;
&lt;th&gt;Issues bad cert&lt;/th&gt;
&lt;th&gt;Doesn&amp;#39;t&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;No extortion&lt;/td&gt;
&lt;td&gt;-100000&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extortion&lt;/td&gt;
&lt;td&gt;-100000&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;-1000&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bribery&lt;/td&gt;
&lt;td&gt;-99000&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;Without CT, bribery and extortion change the optimal strategy for the CA - whereas with CT the optimal strategy is always the same, rendering bribery and extortion pointless. &lt;/p&gt;

&lt;p&gt;Granted, bribery and extortion would work if the threat or bribe was greater than putting the CA out of business - but even then, it would only get the attacker one set of certificates which would be detected and revoked in short order. &lt;strong&gt;Certificate Transparency is good for CAs because it makes threat-proof.&lt;/strong&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Some software design principles I've found useful, that you might find useful too</title>
   <link href="https://www.mjt.me.uk/posts/some-general-design-principles-you-might-find-useful/"/>
   <updated>2016-02-22T00:00:00+00:00</updated>
   <id>https://www.mjt.me.uk/posts/some-general-design-principles-you-might-find-useful</id>
   <content type="html">&lt;p&gt;Here are some subjective opinions I&amp;#39;ve developed on software design - I&amp;#39;m &amp;quot;putting them out there&amp;quot; to see what other people think of them, and to explain to people who hear my opinions the thinking behind them.&lt;/p&gt;

&lt;h3 id=&quot;even-the-greatest-dependencies-can-go-down&quot;&gt;Even the greatest dependencies can go down.&lt;/h3&gt;

&lt;p&gt;When you depend on another system, you should ask what you&amp;#39;ll do if that system goes down. If anyone tells you &amp;quot;it will never go down&amp;quot;, they probably don&amp;#39;t know what they&amp;#39;re talking about. Unless &amp;quot;it&amp;quot; is airliner avionics with three independent versions coded by separate companies - and &lt;a href=&quot;http://sunnyday.mit.edu/papers/nver-tse.pdf&quot;&gt;maybe even not then&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.cnet.com/uk/news/amazon-outage-hits-site-globally-prevents-some-customers-from-placing-orders/&quot;&gt;Occasional&lt;/a&gt; &lt;a href=&quot;http://www.theregister.co.uk/2014/12/18/microsoft_tells_blowbyblow_azure_fail_tale/&quot;&gt;multi-hour&lt;/a&gt; &lt;a href=&quot;http://www.bbc.co.uk/news/technology-30996928&quot;&gt;service&lt;/a&gt; &lt;a href=&quot;http://www.networkworld.com/article/2160902/cloud-computing/amazon-ebs-failure-brings-down-reddit--imgur--others.html&quot;&gt;outages&lt;/a&gt; &lt;a href=&quot;http://www.bloomberg.com/bw/articles/2013-08-26/another-amazon-outage-exposes-the-clouds-dark-lining&quot;&gt;are&lt;/a&gt; &lt;a href=&quot;https://googleblog.blogspot.co.uk/2014/01/todays-outage-for-several-google.html&quot;&gt;inevitable&lt;/a&gt;. Amazon.com and gmail can have outages, and who could have have bigger incentives, better practices or better employees than that?&lt;/p&gt;

&lt;h3 id=&quot;divide-your-dependencies-into-those-you-can-and-can-39-t-work-without-and-make-the-second-list-as-short-as-possible&quot;&gt;Divide your dependencies into those you can and can&amp;#39;t work without, and make the second list as short as possible.&lt;/h3&gt;

&lt;p&gt;If you&amp;#39;re writing an service backed by an SQL database, I don&amp;#39;t expect it to keep working if the SQL database is unavailable - but if the service &lt;em&gt;also&lt;/em&gt; relies on a mail-sending service, you can probably still service requests if the mail-sending service has a brief outage.&lt;/p&gt;

&lt;h3 id=&quot;cache-everything-you-can-and-prefer-to-retrieve-all-the-data-to-cache-where-that-39-s-feasible&quot;&gt;Cache everything you can, and prefer to retrieve all the data to cache where that&amp;#39;s feasible.&lt;/h3&gt;

&lt;p&gt;For any reasonably small, reasonably stable dataset - less than a few hundred kilobytes, say - you should try to retrieve the whole dataset and cache it in memory. For example, if your software needs a list of EC2 regions, you should retrieve the entire list, cache it, and periodically refresh it.&lt;/p&gt;

&lt;p&gt;This isn&amp;#39;t just because it&amp;#39;ll be faster - although it will be. It&amp;#39;s also because, if the service you&amp;#39;re getting data from is temporarily unavailable, you&amp;#39;ll be able to soldier on with your cached data.&lt;/p&gt;

&lt;p&gt;The I prefer getting all data to just getting data on demand is to get simple, predictable behaviour. If you load the entire list of EC2 regions, it&amp;#39;s either fully populated or not at all. But if you load entries on demand and some are cached and others are missing, you might end up with confusing failure behaviour where some requests succeed while others fail. It also gives you a simple way to remove items from the cache when they&amp;#39;re removed from the underlying dataset, preventing another possible confusing behaviour.&lt;/p&gt;

&lt;h3 id=&quot;but-raise-a-big-flag-if-a-dependency-is-down-when-your-service-starts-up&quot;&gt;But raise a big flag if a dependency is down when your service starts up.&lt;/h3&gt;

&lt;p&gt;Your production environment should be at least as reliable as your integration testing environment - and it&amp;#39;s normal for integration test environments to be much less reliable, what with all the testing going on (if you have a complex system with a highly reliable test environment, I&amp;#39;d be glad to be corrected on this one).&lt;/p&gt;

&lt;p&gt;If test environments have nine times as many problems as production environments have, and you launch something in your test environment that reports Amazon&amp;#39;s production environment is down, nine times out of ten the problem&amp;#39;s going to be on your end. Maybe you&amp;#39;ve messed up a firewall or proxy or test configuration or security group.&lt;/p&gt;

&lt;p&gt;You should make this raise a big red flag in your test environment - something so abundantly clear the people testing can&amp;#39;t possibly miss it. You could prevent the service from starting up at all - but that might be inconvenient because of....&lt;/p&gt;

&lt;h3 id=&quot;test-what-you-fly-fly-what-you-test&quot;&gt;Test what you fly, fly what you test&lt;/h3&gt;

&lt;p&gt;When the thing you deploy to production is different to the thing you tested, the differences will bite you in the ass. If at all possible, the file you use for final testing should be exactly the same file you&amp;#39;re going to deploy.&lt;/p&gt;

&lt;p&gt;Example: Your database includes a &amp;quot;last modified by process&amp;quot; column, and any time your program updates a row, it puts its name and version into that column. The version is compiled into your software, and you do a different build with for every environment, with the environment name included in the version string. The previous version wrote ProgramName-1.0-Production and the version in test writes ProgramName-1.0.1-CIT, both were tested and work fine. But ProgramName-1.0.1-Production couldn&amp;#39;t update anything - because the version name was too long to fit into the column.&lt;/p&gt;

&lt;h3 id=&quot;avoid-message-queues-wherever-possible-especially-for-interfaces-between-teams&quot;&gt;Avoid message queues wherever possible, especially for interfaces between teams.&lt;/h3&gt;

&lt;p&gt;With a HTTP API, if the sender sends a malformed message, the receiver can return an error code immediately, so an error is reported close to where it&amp;#39;s called. Your automated integration test can fail, or your operations team get an alert about the right system.&lt;/p&gt;

&lt;p&gt;With a message queue, such a malformed message will only cause an error at the receiver. You&amp;#39;ll need an extra interface if you want to do automated integration testing; and if malformed messages are being sent chances are your operations team will get an alert from the receiver, not the system with the fault.&lt;/p&gt;

&lt;p&gt;I&amp;#39;ve also seen a bunch of other mistakes and faults:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;quot;Our consumer was down and no-one noticed for 4 hours&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;We have a queue size alert, but the alarm threshold is set to avoid false alarms from occasional surges. It takes thirty minutes of traffic to build up before the alert triggered, so our consumer was down and no-one noticed for 30 minutes&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;To detect producers going down, we have an alert if there&amp;#39;s no traffic for a certain time - but because two separate services send to this queue, when one failed the traffic from the other prevented the alert from triggering&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;Our consumer took a batch of messages off the queue, but crashed before putting them into the database. Can you resend the recent messages, please?&amp;quot;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are ways around these problems, but they&amp;#39;re all very clunky compared to just replacing your queue with a HTTP API.&lt;/p&gt;

&lt;h3 id=&quot;if-you-want-to-avoid-vendor-lock-in-you-can-only-use-the-features-of-the-second-best-vendor&quot;&gt;If you want to avoid vendor lock-in, you can only use the features of the second-best vendor.&lt;/h3&gt;

&lt;p&gt;Or more precisely, you can only use the intersection of the features of the first and second best vendors. If the best vendor adds a new feature no-one else has, and you start relying on it, that&amp;#39;s vendor lock-in. And that temptation will be very difficult to resist.&lt;/p&gt;

&lt;p&gt;I include this point also for people who are trying to convince others of the importance of avoiding vendor lock-in; some people will be difficult to convince for this reason.&lt;/p&gt;

&lt;h3 id=&quot;turn-your-problems-that-happen-once-a-year-into-problems-that-happen-once-a-day&quot;&gt;Turn your problems that happen once a year into problems that happen once a day.&lt;/h3&gt;

&lt;p&gt;Code that runs thousands of times a day is easy to trust - if there were any major problems, they would have already been laid bare by the extensive use.&lt;/p&gt;

&lt;p&gt;Software that only gets run rarely is a different matter. If it&amp;#39;s a rare event that you have to update that huge file perhaps you&amp;#39;ll find someone else has used the disk space you were relying on using; if it&amp;#39;s rare you have a server failure perhaps you&amp;#39;ll find your failover server is missing some critical configuration or your clients can&amp;#39;t gracefully failover; if it&amp;#39;s a rare event that you update your SSL certificates, perhaps you&amp;#39;ll forget to do it all together.&lt;/p&gt;

&lt;p&gt;The simplest way to make the rare events as reliable as the regular events is to turn the rare events &lt;em&gt;into&lt;/em&gt; regular events. This is the idea behind Netflix&amp;#39;s &lt;a href=&quot;http://techblog.netflix.com/2011/07/netflix-simian-army.html&quot;&gt;Chaos Monkey&lt;/a&gt; - but you don&amp;#39;t have to limit it to server failures. If you want people consuming from your queues to support multiple deliveries, make sure they get multiple deliveries; and if you want your web service clients to retry when they get a retryable error, make sure they get them regularly.&lt;/p&gt;

&lt;p&gt;Needless to say, you&amp;#39;ll find this a lot easier to introduce at the &lt;em&gt;start&lt;/em&gt; of a software project.&lt;/p&gt;

&lt;h3 id=&quot;build-servers-are-great-but-never-lose-the-ability-for-developers-to-build-locally&quot;&gt;Build servers are great, but never lose the ability for developers to build locally.&lt;/h3&gt;

&lt;p&gt;If you let the build server turn into a black box with behaviour nobody else can replicate, you&amp;#39;re going to have a bad time.&lt;/p&gt;

&lt;p&gt;Being able to do a full build locally is super useful when you have problems with your build server - the people who aren&amp;#39;t fixing the build server can keep working, and the people who are fixing the build server can test things locally and compare their results to those of the build server. And even if you never need to understand your build server in order to fix it, at some point you&amp;#39;re going to want to add capabilities or upgrade it, so you still need to understand it.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>The smallest 256x256 single-color PNG file, and where you've seen it</title>
   <link href="https://www.mjt.me.uk/posts/smallest-png/"/>
   <updated>2015-10-24T00:00:00+01:00</updated>
   <id>https://www.mjt.me.uk/posts/smallest-png</id>
   <content type="html">&lt;p&gt;Do you recognise these images? There&amp;#39;s a good chance you&amp;#39;ve seen some of them before now, probably several times. Here&amp;#39;s a hint: They all depict the same thing.&lt;/p&gt;

&lt;figure&gt;
  &lt;img src=&quot;/assets/images/smallest-png/openstreetmap.png&quot; alt=&quot;Blue square&quot;&gt;
  &lt;figcaption&gt;103 bytes&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;
  &lt;img src=&quot;/assets/images/smallest-png/bing-maps.png&quot; alt=&quot;Blue square&quot;&gt;
  &lt;figcaption&gt;156 bytes&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;
  &lt;img src=&quot;/assets/images/smallest-png/google-maps.png&quot; alt=&quot;Blue square&quot;&gt;
  &lt;figcaption&gt;178 bytes&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;
  &lt;img src=&quot;/assets/images/smallest-png/skobbler-maps.png&quot; alt=&quot;Blue square&quot;&gt;
  &lt;figcaption&gt;379 bytes&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;
  &lt;img src=&quot;/assets/images/smallest-png/tomtom-redirected.png&quot; alt=&quot;Blue square&quot;&gt;
  &lt;figcaption&gt;921 bytes&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;
  &lt;img src=&quot;/assets/images/smallest-png/here-maps-256px.png&quot; alt=&quot;Blue square&quot;&gt;
  &lt;figcaption&gt;1,189 bytes&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;They all look pretty similar - so why the size difference?&lt;/p&gt;

&lt;h3 id=&quot;a-quick-intro-to-png&quot;&gt;A quick intro to PNG&lt;/h3&gt;

&lt;style&gt;
.length { background-color:#5DDFE8; }
.chunktype { background-color:#5DE87D; }
.data { background-color:#ACE85D; }
.crc { background-color:#E85DE6; }
.B5D0D0 { background-color:#B5D0D0; }
&lt;/style&gt;

&lt;p&gt;The basic PNG file is comprised of recurring chunks. Each chunk is comprised of four parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;span class=&quot;length&quot;&gt;Length of the data block (four bytes)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;  &lt;span class=&quot;chunktype&quot;&gt;Chunk type (four bytes)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;  &lt;span class=&quot;data&quot;&gt;Data&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;  &lt;span class=&quot;crc&quot;&gt;CRC (four bytes)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here&amp;#39;s the hex content of the smallest PNG shown above - the 103 byte file:&lt;/p&gt;

&lt;pre&gt;
89 50 4E 47  0D 0A 1A 0A  &lt;span class=&quot;length&quot;&gt;00 00 00 0D&lt;/span&gt;  &lt;span class=&quot;chunktype&quot;&gt;49 48 44 52&lt;/span&gt; | .PNG........&lt;span class=&quot;chunktype&quot;&gt;IHDR&lt;/span&gt;
&lt;span class=&quot;data&quot;&gt;00 00 01 00  00 00 01 00  01 03 00 00  00&lt;/span&gt; &lt;span class=&quot;crc&quot;&gt;66 BC 3A&lt;/span&gt; | .............f¼:
&lt;span class=&quot;crc&quot;&gt;25&lt;/span&gt; &lt;span class=&quot;length&quot;&gt;00 00 00  03&lt;/span&gt; &lt;span class=&quot;chunktype&quot;&gt;50 4C 54  45&lt;/span&gt; &lt;span class=&quot;data&quot;&gt;B5 D0 D0&lt;/span&gt;  &lt;span class=&quot;crc&quot;&gt;63 04 16 EA&lt;/span&gt; | %....&lt;span class=&quot;chunktype&quot;&gt;PLTE&lt;/span&gt;µÐÐc..ê
&lt;span class=&quot;length&quot;&gt;00 00 00 1F&lt;/span&gt;  &lt;span class=&quot;chunktype&quot;&gt;49 44 41 54&lt;/span&gt;  &lt;span class=&quot;data&quot;&gt;68 81 ED C1  01 0D 00 00&lt;/span&gt; | ....&lt;span class=&quot;chunktype&quot;&gt;IDAT&lt;/span&gt;h.íÁ....
&lt;span class=&quot;data&quot;&gt;00 C2 A0 F7  4F 6D 0E 37  A0 00 00 00  00 00 00 00&lt;/span&gt; | .Â ÷Om.7 .......
&lt;span class=&quot;data&quot;&gt;00 BE 0D 21  00 00 01&lt;/span&gt; &lt;span class=&quot;crc&quot;&gt;9A  60 E1 D5&lt;/span&gt; &lt;span class=&quot;length&quot;&gt;00  00 00 00&lt;/span&gt; &lt;span class=&quot;chunktype&quot;&gt;49&lt;/span&gt; | .¾.!....`áÕ....&lt;span class=&quot;chunktype&quot;&gt;I&lt;/span&gt;
&lt;span class=&quot;chunktype&quot;&gt;45 4E 44&lt;/span&gt; &lt;span class=&quot;crc&quot;&gt;AE  42 60 82&lt;/span&gt;                              | &lt;span class=&quot;chunktype&quot;&gt;END&lt;/span&gt;®B`.         
&lt;/pre&gt;

&lt;p&gt;The &lt;strong&gt;IHDR&lt;/strong&gt; section - &lt;a href=&quot;http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html&quot;&gt;further specification here&lt;/a&gt; - marks this as a 256x256 pixel image (00 00 01 00  00 00 01 00), 1 bit depth (01), with each pixel represented as an index into a palette (03). The image uses the default deflate compression (00), basic filtering (00) and no interlacing (00).&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;PLTE&lt;/strong&gt; section is mandatory for paleted images (PNG also supports true color images, where it isn&amp;#39;t required) - it can contain up to 256 entries, but this one only contains a single entry - &lt;span class=&quot;B5D0D0&quot;&gt;B5 D0 D0&lt;/span&gt; - as only a single color is needed. This is also an example of a &amp;quot;truncated palette&amp;quot; - the one-bit depth selected in the IHDR section allows 2 colors, but as only one color is used, only one is included in the palette.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;IDAT&lt;/strong&gt; section is the actual image data. It&amp;#39;s 31 bytes long, compressed with the &lt;a href=&quot;https://en.wikipedia.org/wiki/DEFLATE&quot;&gt;DEFLATE&lt;/a&gt; algorithm. If you &lt;a href=&quot;https://gist.github.com/michaeltandy/c051db2243e679e78a37&quot;&gt;inflate the data in this example&lt;/a&gt;, you get 8448 bytes of zeros. Why 8448? Well, 8192 bytes correspond to the pixels at one bit per pixel ( 256*256/8 = 8192 ) and 256 correspond to one byte for each line of the image, specifying a &lt;a href=&quot;http://www.libpng.org/pub/png/spec/1.2/PNG-Filters.html&quot;&gt;filter to apply&lt;/a&gt;. In our case, the filter byte is always 0 which corresponds to no filtering being performed.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;IEND&lt;/strong&gt; section marks the end of the image.&lt;/p&gt;

&lt;h3 id=&quot;why-the-differences-in-size-between-the-images-above&quot;&gt;Why the differences in size between the images above?&lt;/h3&gt;

&lt;style&gt;
table, th, td { padding: 15px; }
th, td { border: 2px solid black; }
&lt;/style&gt;

&lt;table&gt;&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;Explanation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;103 bytes&lt;/td&gt;
&lt;td&gt;Palettised, 1 bit per pixel, 3 byte PLTE, 31 byte IDAT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;156 bytes&lt;/td&gt;
&lt;td&gt;Palettised, 8 bits per pixel, 3 byte PLTE, 84 byte IDAT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;178 bytes&lt;/td&gt;
&lt;td&gt;Palettised, 8 bits per pixel, 3 byte PLTE, 85 byte IDAT, &lt;a href=&quot;http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html#C.pHYs&quot;&gt;pHYs section&lt;/a&gt; (physical pixel dimensions)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;379 bytes&lt;/td&gt;
&lt;td&gt;Palettised, 8 bits per pixel, 3 byte PLTE, 307 byte IDAT (The IDAT has the same all-zeros content as the two images previously - just a less effective compression algorithm?)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;921 bytes&lt;/td&gt;
&lt;td&gt;Palettised, 8 bits per pixel, 768 byte PLTE (with padding in all but the first three bytes), 84 byte IDAT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1,189 bytes&lt;/td&gt;
&lt;td&gt;Palettised, 8 bits per pixel, 768 byte PLTE (with padding in all but the first three bytes), 84 byte IDAT, 256 byte &lt;a href=&quot;http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html&quot;&gt;tRNS section&lt;/a&gt; (transparency data for palette entries, padding in all but the first byte)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;(The last one is actually served by redirecting to a cached resource, so it doesn&amp;#39;t work out that bad compared to the others)&lt;/p&gt;

&lt;h3 id=&quot;why-would-it-take-84-bytes-to-represent-data-that-was-all-zeros-haven-39-t-these-people-heard-of-run-length-encoding&quot;&gt;Why would it take 84 bytes to represent data that was all zeros? Haven&amp;#39;t these people heard of run length encoding?&lt;/h3&gt;

&lt;p&gt;The deflate algorithm is used to compress the IDAT section of PNGs, and it does support run length encoding - but the run length is represented as an 8-bit huffman-encoded number; the &lt;a href=&quot;http://www.zlib.net/zlib_tech.html&quot;&gt;theoretical maximumn compression ratio for deflate is about 1030.3 : 1&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;We don&amp;#39;t achieve that theoretical maximum in practice (there are fixed overheads for things like defining the dictionary). The compression ratios we see include 264.2:1 for the 103 byte file and 780.1:1 for the 156 byte file.&lt;/p&gt;

&lt;h3 id=&quot;so-who-needs-these-micro-optimisations&quot;&gt;So who needs these micro-optimisations?&lt;/h3&gt;

&lt;p&gt;Here&amp;#39;s the 103 byte image in a more familiar context:&lt;/p&gt;

&lt;style&gt;
.leaflet-tile { border: 2px solid black; }
&lt;/style&gt;

&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.5/leaflet.js&quot;&gt;&lt;/script&gt;

&lt;div id=&quot;map&quot; style=&quot;height:90vh; max-height:800px;&quot;&gt;&lt;/div&gt;

&lt;script&gt;
var map = L.map('map').setView([54.8, -10.9], 6);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 15,
attribution: 'Map data &amp;copy; &lt;a href=&quot;http://openstreetmap.org&quot;&gt;OpenStreetMap&lt;/a&gt; contributors, &lt;a href=&quot;http://creativecommons.org/licenses/by-sa/2.0/&quot;&gt;CC-BY-SA&lt;/a&gt;',
id: 'osm'
}).addTo(map);
&lt;/script&gt;

&lt;p&gt;Map tiles representing the sea!&lt;/p&gt;

&lt;p&gt;Slippy maps traditionally serve fixed size &amp;#39;map tiles&amp;#39; in a grid at a given zoom level - for example http://b.tile.openstreetmap.org/6/29/20.png would be zoom level 6, the 29th column, and the 20th row; http://a.tile.openstreetmap.org/19/516664/319949.png would be zoom level 19, column 516664, row 319949. The higher the zoom level, the more tiles are needed to show the entire planet - and there&amp;#39;s a whole lot of sea within that data. Depending on the size of your monitor, you might have downloaded 10 or more all-sea tiles just to render that map above, and that&amp;#39;s before you&amp;#39;ve zoomed in or scrolled around.&lt;/p&gt;

&lt;p&gt;Servers could send a redirect to a cached resource - some maps do exactly that! But when you can send a tile in just 103 bytes, sending the tile is as simple as sending the redirect. &lt;/p&gt;

&lt;table&gt;&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;Map provider&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;103 bytes&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://openstreetmap.org&quot;&gt;OpenStreetMap&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://b.tile.openstreetmap.org/12/4025/2501.png&quot;&gt;Example&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;156 bytes&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.bing.com/maps/&quot;&gt;Bing Maps&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://t3.ssl.ak.dynamic.tiles.virtualearth.net/comp/ch/031213202023?mkt=en-gb&amp;amp;it=G,VE,BX,L,LA&amp;amp;shading=hill&amp;amp;og=104&amp;amp;n=z&quot;&gt;Example&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;178 bytes&lt;/td&gt;
&lt;td&gt;Google Maps (classic)&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://mts1.googleapis.com/vt?pb=!1m5!1m4!1i8!2i131!3i79!4i256!2m3!1e0!2sm!3i325000000!3m9!2sen-GB!3sUS!5e18!12m1!1e47!12m3!1e37!2m1!1ssmartmaps!4e0&quot;&gt;Example&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;379 bytes&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;http://maps.skobbler.com&quot;&gt;Skobbler Maps&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;http://tiles3-bc7b4da77e971c12cb0e069bffcf2771.skobblermaps.com/TileService/tiles/2.0/01021113210/7/6/32/46.png&quot;&gt;Example&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;921 bytes&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;http://routes.tomtom.com&quot;&gt;TomTom&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;http://c.api.internal.tomtom.com/lbs/map/3/basic/1/7/42/56.png?key=dvbfcb88hkrje9ur2fs84uxn&quot;&gt;Example&lt;/a&gt; (actually a redirect - so the size of the initial image doesn&amp;#39;t matter that much)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1,189 bytes&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.here.com/&quot;&gt;here.com&lt;/a&gt; (Navteq)&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://1.base.maps.api.here.com/maptile/2.1/maptile/cda3b29e40/normal.day/9/260/159/256/png8?app_id=xWVIueSv6JL0aJ5xqTxb&amp;amp;app_code=djPZyynKsbTjIUDOBcHZ2g&amp;amp;lg=eng&amp;amp;ppi=72&quot;&gt;Example&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

&lt;h3 id=&quot;got-any-other-tricks-up-your-sleeve&quot;&gt;Got any other tricks up your sleeve?&lt;/h3&gt;

&lt;figure style=&quot;float:right&quot;&gt;
  &lt;img src=&quot;/assets/images/smallest-png/rgb-1px.png&quot; width=&quot;256px&quot; height=&quot;256px&quot; alt=&quot;Blue square&quot;&gt;
  &lt;figcaption&gt;69 bytes - if all your clients support scaling&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Instead of serving a 256x256px image, you can serve a 1px image and tell the browser to scale it up. Of course, if you have to put width= &amp;quot;256px&amp;quot; height= &amp;quot;256px&amp;quot; into your HTML that adds 30 bytes to your HTML! But if you&amp;#39;re inserting the DOM nodes programmatically using javascript (such as for a slippy map) this isn&amp;#39;t a problem.&lt;/p&gt;

&lt;p&gt;When you make a very small image it&amp;#39;s actually more efficient to use a true color image instead of a palettised image, as each extra segment in the PNG file adds 12 bytes of length, header and CRC information. But that benefit quickly diminishes as image size increases; converting the 103 byte file to true color increases its size to 567 bytes.&lt;/p&gt;

&lt;p&gt;Some slippy maps use larger tiles; a 512px tile, taking up 126 bytes, can replace four 256px tiles taking up 412 bytes between them as well as overhead for http headers. But in areas where tiles show more data, you&amp;#39;ll use relatively more bandwidth on things outside the viewport, which won&amp;#39;t be shown unless the user scrolls. Some versions of Google Maps use 512px tiles, as does here.com.&lt;/p&gt;

&lt;p&gt;TomTom doesn&amp;#39;t serve the 921 byte tile repeatedly - instead users get a HTTP 302 redirect with header &amp;quot;Location: http://s3.amazonaws.com/mascoma-renderer-static-san-prod/rialto/water.png&amp;quot; which is an 84-byte header - but it means users only have to retrieve the generic water tile once; thereafter it&amp;#39;s served from the browser cache. The gains can be even greater if you want something more complicated than a single-color image!&lt;/p&gt;

&lt;p&gt;Of course, no matter how small you get your PNG you&amp;#39;ll still have to send 400+ bytes of HTTP headers in each direction!&lt;/p&gt;

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

&lt;p&gt;You can make a PNG pretty small if you want to, and different software and settings can produce files that vary in size quite a bit.&lt;/p&gt;

&lt;p&gt;If you&amp;#39;re doing something that involves moving lots of small PNGs around, a hex editor is all you need to check you&amp;#39;re using the minimum number of bits per pixel, your palette is truncated, and you don&amp;#39;t have any data segments you don&amp;#39;t absolutely need.&lt;/p&gt;

&lt;p&gt;The compression in PNG files isn&amp;#39;t as good as the &lt;a href=&quot;https://en.wikipedia.org/wiki/Shannon&amp;#x27;s_source_coding_theorem&quot;&gt;source coding theorem&lt;/a&gt; would hope for, and large blocks of identical data don&amp;#39;t compress down to nothing as completely as you might hope for.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Contraction Hierarchies path finding algorithm, illustrated using three.js</title>
   <link href="https://www.mjt.me.uk/posts/contraction-hierarchies/"/>
   <updated>2015-06-12T00:00:00+01:00</updated>
   <id>https://www.mjt.me.uk/posts/contraction-hierarchies</id>
   <content type="html">&lt;script src=&quot;/assets/images/contraction-hierarchies/threejs/three.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;/assets/images/contraction-hierarchies/threejs/OrbitControls.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;/assets/images/contraction-hierarchies/threejs/stats.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;/assets/images/contraction-hierarchies/threejs/detector.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;/assets/images/contraction-hierarchies/ladder-geometry.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;/assets/images/contraction-hierarchies/ladder-contraction-sequence.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;/assets/images/contraction-hierarchies/ladder-two-searches.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;/assets/images/contraction-hierarchies/3dmap.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Have you ever wondered how Google Maps can calculate driving directions so fast? Google can calculate driving directions in &lt;a href=&quot;http://tools.pingdom.com/fpt/#!/bHpLRM/http://maps.googleapis.com/maps/api/directions/json?origin=51.58983,-0.20017&amp;amp;destination=51.33495,-0.16695&amp;amp;sensor=false&quot;&gt;100-500 milliseconds&lt;/a&gt;, whereas back in 1990s it took my father&amp;#39;s 386sx about 30 minutes to calculate such a route.&lt;/p&gt;

&lt;p&gt;If you&amp;#39;ve done much programming, you probably already know the basics of this. Road maps can be represented, in the jargon, as &amp;quot;graphs&amp;quot;, where junctions are &amp;quot;nodes&amp;quot; and roads between junctions are &amp;quot;edges&amp;quot; and the time taken to drive down each edge is its &amp;quot;cost&amp;quot;. Finding the fastest route between two locations is then a matter of finding the shortest path between nodes of the graph.&lt;/p&gt;

&lt;p&gt;Traditional algorithms for finding such routes include &lt;a href=&quot;https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm&quot;&gt;Dijkstra&amp;#39;s Algorithm&lt;/a&gt; and the &lt;a href=&quot;https://en.wikipedia.org/wiki/A*_search_algorithm&quot;&gt;A* algorithm&lt;/a&gt;. If you haven&amp;#39;t heard of those, go read the wikipedia pages - because the rest of this post is going to assume you know them!&lt;/p&gt;

&lt;p&gt;There are several algorithms that are a lot faster and more memory efficient than Dijkstra&amp;#39;s Algorithm. They rely on doing a bunch of time-consuming preprocessing on the graph; once the graph is processed individual queries can run a lot faster. This post is about the &amp;quot;contraction hierarchies&amp;quot; algorithm, one of the simpler algorithms that does this.&lt;/p&gt;

&lt;p&gt;This algorithm isn&amp;#39;t my invention - it was proposed by &lt;a href=&quot;http://algo2.iti.kit.edu/schultes/hwy/contract.pdf&quot;&gt;Robert Geisberger, Peter Sanders, Dominik Schultes, and Daniel Delling of Universitat Karlsruhe&lt;/a&gt; - and I can&amp;#39;t guarantee Google use this specific algorithm. I&amp;#39;m sure they use something similar, though!&lt;/p&gt;

&lt;h2 id=&quot;preprocessing-the-graph&quot;&gt;Preprocessing the graph&lt;/h2&gt;

&lt;p&gt;We preprocess the graph by &amp;quot;contracting&amp;quot; the nodes one at a time.&lt;sup&gt;Wondering how we choose the order? Read on to find out&lt;/sup&gt; We number nodes in the order we contract them. To perform the contraction we work out every shortest path between the node&amp;#39;s immediate neighbors and insert &amp;quot;shortcuts&amp;quot; for them, then we mark the node as processed.&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s a simple graph, before and after a node is contracted:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/contraction-hierarchies/fivenode.svg&quot; alt=&quot;The graph before and after contraction&quot;&gt;&lt;/p&gt;

&lt;p&gt;To contract C we insert shortcuts from A to E and from A to B because A-&amp;gt;C-&amp;gt;E and A-&amp;gt;C-&amp;gt;B are shortest routes. We don&amp;#39;t need to insert a shortcut from B to E because B-&amp;gt;C-&amp;gt;E isn&amp;#39;t the shortest route from B to E. B-&amp;gt;D-&amp;gt;E is shorter.&lt;/p&gt;

&lt;p&gt;Contracting doesn&amp;#39;t completely delete a node - but the node can be ignored for the rest of the contraction process, because when we see an edge going toward C we know there&amp;#39;s either a shortcut or it isn&amp;#39;t a shortest path; either way, we don&amp;#39;t need to visit C. If we do a search that starts or ends at C we&amp;#39;ll still be able to find it - you&amp;#39;ll see how later in the post.&lt;/p&gt;

&lt;p&gt;What about when there are two routes to an end point, both routes exactly the same length? If you want to find all such routes, you should insert a shortcut whenever it&amp;#39;s the same length as the shortest path; if you don&amp;#39;t want multiple results, you only need to insert shortcuts when they&amp;#39;re the &lt;em&gt;only&lt;/em&gt; shortest path. Two routes exactly the same length is unusual with the way roads are usually laid out in the UK, but it might be relevant in cities laid out as grids, or when pathfinding for video game AIs where the game uses a grid layout.&lt;/p&gt;

&lt;h3 id=&quot;a-visualisation-of-the-contraction-process&quot;&gt;A visualisation of the contraction process&lt;/h3&gt;

&lt;p&gt;Here&amp;#39;s an animation showing the contraction process.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cyan markers identify individual nodes&lt;/li&gt;
&lt;li&gt;Node heights indicate their position in the contraction order - the highest being nodes that haven&amp;#39;t been contracted yet&lt;/li&gt;
&lt;li&gt;Blue lines are edges from the original graph.&lt;/li&gt;
&lt;li&gt;Green lines mark where shortcuts are inserted.&lt;/li&gt;
&lt;li&gt;White lines show the original graph in 2D, for comparison.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As this is implemented in three.js you should be able to scroll around with gestures, or with your mouse or keyboard - give it a go!&lt;/p&gt;

&lt;div style=&quot;float: left; width: 100%; padding-bottom:10px&quot;&gt;
&lt;div id=&quot;contraction1&quot; style=&quot;float: left; width: 70%; height:100vh; max-height:800px; position:relative&quot;&gt;&lt;/div&gt;
&lt;div style=&quot;float: left; width: 30%; overflow-y: scroll; height:100vh; max-height:800px;&quot;&gt;&lt;ul id=&quot;contraction1_console&quot;&gt;&lt;/ul&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;new threemap(document.getElementById(&quot;contraction1&quot;),geom,contraSeq,1,document.getElementById(&quot;contraction1_console&quot;));&lt;/script&gt;

&lt;h3 id=&quot;so-how-come-the-nodes-get-contracted-in-that-order&quot;&gt;So how come the nodes get contracted in that order?&lt;/h3&gt;

&lt;p&gt;The algorithm will produce correct results regardless of the contraction order - but how much of a performance improvement you get depends on the contraction order.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://algo2.iti.kit.edu/schultes/hwy/contract.pdf&quot;&gt;Papers on the algorithm&lt;/a&gt; have evaluated several heuristics to choose node orders.&lt;/p&gt;

&lt;p&gt;Usually we prefer contractions that reduce the number of edges, after added shortcuts are taken into account. Better to do a contraction that removes five edges than a contraction that only removes four!&lt;/p&gt;

&lt;p&gt;We also try to keep contraction depths roughly even across the map - if you had a hundred nodes in a row and you contracted them from right to left, you wouldn&amp;#39;t have to add any shortcuts - but to path from one end to the other you&amp;#39;d have to visit every node. On the other hand if you contract every other node the contracted graph will look more like a binary tree, and the search process will have to visit fewer nodes.&lt;/p&gt;

&lt;p&gt;There are a bunch of other heuristics you can apply - see the paper linked above for examples.&lt;/p&gt;

&lt;h2 id=&quot;finding-the-shortest-path&quot;&gt;Finding the shortest path&lt;/h2&gt;

&lt;p&gt;To find the shortest path between two nodes we perform two searches - one from the start node, one from the end node - then we see where they meet. Let&amp;#39;s assume we want to find the route between node 1 and node 8.&lt;/p&gt;

&lt;h3 id=&quot;search-from-the-start-node&quot;&gt;Search from the start node&lt;/h3&gt;

&lt;p&gt;The search is similar to Djikstra&amp;#39;s algorithm - but with one extra rule: We only follow edges going to nodes with a higher contraction order than the current node. In our visualisation, this means we only ever follow edges that slope upwards:&lt;/p&gt;

&lt;div style=&quot;float: left; width: 100%; padding-bottom:10px&quot;&gt;
&lt;div id=&quot;search1&quot; style=&quot;float: left; width: 70%; height:100vh; max-height:800px; position:relative&quot;&gt;&lt;/div&gt;
&lt;div style=&quot;float: left; width: 30%; overflow-y: scroll; height:100vh; max-height:800px;&quot;&gt;&lt;ul id=&quot;search1_console&quot;&gt;&lt;/ul&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;new threemap(document.getElementById(&quot;search1&quot;),geom,contraSeq,2,document.getElementById(&quot;search1_console&quot;),searchFromNode1);&lt;/script&gt;

&lt;h3 id=&quot;search-from-the-end-node&quot;&gt;Search from the end node&lt;/h3&gt;

&lt;p&gt;The search from the end node works the same way. If your graph has directed edges, the search from the end node will go follow edges in the reverse direction. For simplicity, all edges in this visualisation are bidirectional. &lt;/p&gt;

&lt;div style=&quot;float: left; width: 100%; padding-bottom:10px&quot;&gt;
&lt;div id=&quot;search2&quot; style=&quot;float: left; width: 70%; height:100vh; max-height:800px; position:relative&quot;&gt;&lt;/div&gt;
&lt;div style=&quot;float: left; width: 30%; overflow-y: scroll; height:100vh; max-height:800px;&quot;&gt;&lt;ul id=&quot;search2_console&quot;&gt;&lt;/ul&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;new threemap(document.getElementById(&quot;search2&quot;),geom,contraSeq,2,document.getElementById(&quot;search2_console&quot;),searchFromNode8);&lt;/script&gt;

&lt;h3 id=&quot;combining-the-forward-and-reverse-searches&quot;&gt;Combining the forward and reverse searches&lt;/h3&gt;

&lt;p&gt;We take the lists of nodes visited in the forward and reverse searches and find the intersection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From node 1:&lt;/strong&gt;
&lt;pre&gt;
Node 1 reached immediately
&lt;b&gt;Node 2 reached at cost 1, via 1-&amp;gt;2&lt;/b&gt;
Node 9 reached at cost 4, via 1-&amp;gt;2-&amp;gt;9 (2-&amp;gt;9 via shortcut 2-&amp;gt;7-&amp;gt;9)
&lt;/pre&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From node 8:&lt;/strong&gt;
&lt;pre&gt;
Node 8 reached immediately
Node 3 reached at cost 1, via 8-&amp;gt;3
Node 7 reached at cost 1, via 8-&amp;gt;3
Node 9 reached at cost 1, via 8-&amp;gt;9
&lt;b&gt;Node 2 reached at cost 2, via 8-&amp;gt;3-&amp;gt;2&lt;/b&gt;
Node 4 reached at cost 2, via 8-&amp;gt;3-&amp;gt;4
&lt;/pre&gt;&lt;/p&gt;

&lt;p&gt;Putting one route after the other, we cna get from node 1 to node 8 via 1-&amp;gt;2-&amp;gt;3-&amp;gt;8 at cost 3.&lt;/p&gt;

&lt;p&gt;If the result sets had several entries in common, we would choose the one with the lowest cost.&lt;/p&gt;

&lt;h2 id=&quot;visiting-eight-nodes-out-of-ten-doesn-39-t-seem-like-much-of-an-improvement&quot;&gt;Visiting eight nodes out of ten doesn&amp;#39;t seem like much of an improvement?&lt;/h2&gt;

&lt;p&gt;Right, but drawing ten nodes makes for a simpler animation! Let&amp;#39;s look at a 40x2 grid, with a total of 80 nodes:&lt;/p&gt;

&lt;script src=&quot;/assets/images/contraction-hierarchies/big-grid-geometry.js&quot;&gt;&lt;/script&gt;

&lt;div style=&quot;float: left; width: 100%; padding-bottom:10px&quot;&gt;
&lt;div id=&quot;tenByTen&quot; style=&quot;float: left; width: 70%; height:100vh; max-height:800px; position:relative&quot;&gt;&lt;/div&gt;
&lt;div style=&quot;float: left; width: 30%; overflow-y: scroll; height:100vh; max-height:800px;&quot;&gt;&lt;ul id=&quot;tenByTen_console&quot;&gt;&lt;/ul&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;new threemap(document.getElementById(&quot;tenByTen&quot;),bigGridGeom,bigGridContractionSequence,101,document.getElementById(&quot;tenByTen_console&quot;),bigGridFirstSearch,bigGridSecondSearch);&lt;/script&gt;

&lt;p&gt;The first search sequence visits 11 nodes, the second search 13. That&amp;#39;s a total of 24 nodes out of 80 visited, to discover a path 39 segments long.&lt;/p&gt;

&lt;h2 id=&quot;so-what-would-a-search-of-an-entire-country-involve&quot;&gt;So what would a search of an entire country involve?&lt;/h2&gt;

&lt;p&gt;I live in the UK, so I&amp;#39;ve been processing OpenStreetMap data for the UK.&lt;/p&gt;

&lt;p&gt;Below you can see the two searches required to find the shortest path between &lt;a href=&quot;https://www.openstreetmap.org/node/60455099&quot;&gt;Albert Drive in Glasgow&lt;/a&gt; and &lt;a href=&quot;https://www.openstreetmap.org/node/18670884&quot;&gt;Herbal Hill in Islington, London&lt;/a&gt;. The map is shown as a png because &lt;a href=&quot;http://geojson.io/#data=data:text/x-url,http%3A%2F%2Fgist.githubusercontent.com%2Fmichaeltandy%2Fced8084812566126b868%2Fraw%2Fuk-up-down-shortest.js&quot;&gt;the interactive map&lt;/a&gt; usually gives me an &amp;#39;unresponsive script&amp;#39; warning.&lt;/p&gt;

&lt;p&gt;The search starting in Edinburgh is shown in blue; the search starting in London in red; and the shortest path in black.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/contraction-hierarchies/london-to-edinburgh.png&quot; alt=&quot;London-to-edinburgh map&quot;&gt;
&lt;a href=&quot;https://www.mapbox.com/about/maps/&quot;&gt;Tiles © Mapbox&lt;/a&gt;, &lt;a href=&quot;https://www.openstreetmap.org/about/&quot;&gt;Map data © OpenStreetMap&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The UK map data contains 3,478,051 nodes and 7,646,738 (non-shortcut) edges. The contraction process added 6,186,168 shortcuts.&lt;/p&gt;

&lt;p&gt;The searches from London and Edinburgh visited at 3,968 and 3,113 nodes respectively, and the solution path found passed through 3,617 nodes.&lt;/p&gt;

&lt;p&gt;For &lt;a href=&quot;https://github.com/michaeltandy/contraction-hierarchies&quot;&gt;my implementation&lt;/a&gt;, the search process took 18ms - plenty fast enough for the 500ms response times Google provides! Contraction for the UK took 55 minutes using a single core on a modern i7 processor, and needed about 10 GB of RAM. You could make the process more RAM- and CPU-efficient if you wanted to!&lt;/p&gt;

&lt;h2 id=&quot;more-info-and-similar-algorithms&quot;&gt;More info and similar algorithms&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ad-wiki.informatik.uni-freiburg.de/teaching/EfficientRoutePlanningSS2011&quot;&gt;Hannah Bast from Universität Freiburg has a nice set of lectures on route planning&lt;/a&gt; - I figured out most of my implementation from lecture slides like these, because papers containing symbols like ∀ and ⊆ intimidate me :)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://algo2.iti.kit.edu/documents/routeplanning/geisberger_dipl.pdf&quot;&gt;Robert Geisberger&amp;#39;s 2008 thesis&lt;/a&gt; provides lots more details on contraction hierarchies, and comparisons to other algorithms. &lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://algo2.iti.kit.edu/schultes/hwy/hhJournalSubmit.pdf&quot;&gt;Highway Hierarchies&lt;/a&gt; divides the road network into neighborhoods and highways. Personally I found Sanders and Schultes&amp;#39;s algorithm harder to understand than contraction hierarchies, but they report good performance.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.mpi-inf.mpg.de/%7Ebast/papers/transit-dimacs.pdf&quot;&gt;Transit node routing&lt;/a&gt; identifies important traffic junctions (such as freeway and motorway onramps) and creates a lookup table containing the shortest paths between all such junctions. &lt;/li&gt;
&lt;li&gt;Travel networks with timetables or varying road speeds &lt;a href=&quot;https://algo2.iti.kit.edu/download/time_table_ch.pdf&quot;&gt;have also been addressed by Geisberger&lt;/a&gt; as have &lt;a href=&quot;http://arxiv.org/pdf/1010.0809.pdf&quot;&gt;one-to-many&lt;/a&gt; travel time computations.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=-0ErpE8tQbw&quot;&gt;A google tech talk by Peter Sanders&lt;/a&gt; covers quite a bit about fast route planning.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The contraction hierarchies algorithm is actually fairly simple, and makes path finding very quick - easily below the &lt;a href=&quot;http://www.nngroup.com/articles/response-times-3-important-limits/&quot;&gt;100ms industry standard for web pages&lt;/a&gt;. If you only want to know total travel time, you have to visit fewer nodes than there are in the path!&lt;/p&gt;

&lt;p&gt;The animated 3D graphics were made using &lt;a href=&quot;http://threejs.org/&quot;&gt;three.js&lt;/a&gt; - previously my only 3D experience has been with JOGL and I have to say I found three.js a lot easier!&lt;/p&gt;

&lt;p&gt;At the time of writing, there&amp;#39;s an &lt;a href=&quot;http://donate.openstreetmap.org&quot;&gt;OpenStreetMap fundraising drive&lt;/a&gt; to upgrade a database server? I couldn&amp;#39;t have written this post without their map data, and the project has an annual budget of just $85k. Maybe you&amp;#39;d like to donate?&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Fake £2 coin</title>
   <link href="https://www.mjt.me.uk/posts/fake-coin/"/>
   <updated>2014-12-19T00:00:00+00:00</updated>
   <id>https://www.mjt.me.uk/posts/fake-coin</id>
   <content type="html">&lt;p&gt;A few months ago I was handed some change which I didn&amp;#39;t look at closely.
Later, I realised I&amp;#39;d been given a fake £2 coin.
I searched online and found lots of press coverage about fake £1 coins, but not much about the £2 coin.
So here are some pictures!&lt;/p&gt;

&lt;p&gt;As you can see, the fake is a slightly different colour
and the detail is a lot less clear:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/fake-coin/face1.jpg&quot; alt=&quot;Obverse of real and fake coin, side by side&quot;&gt;&lt;/p&gt;

&lt;p&gt;The fake coin bimetallic - the gold outer ring is a separate bit of metal
not just painted on. But the gap between the two metals isn&amp;#39;t very consistent.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/fake-coin/face2.jpg&quot; alt=&quot;Obverse of real and fake coins&quot;&gt;&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s the reverse side:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/fake-coin/tail1.jpg&quot; alt=&quot;Reverse of real and fake coin, side by side&quot;&gt;&lt;/p&gt;

&lt;p&gt;The forger reproduced the texturing on the one-but-innermost of the three concentric circles,
but not on the innermost circle, for some reason.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/fake-coin/tail2.jpg&quot; alt=&quot;Reverse of real and fake coins&quot;&gt;&lt;/p&gt;

&lt;p&gt;The edge includes milling and engraving
In fact the text on the fake is better centered than the real coin!
(Or I have two fakes, just one is much more convincing than the other)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/fake-coin/edge.jpg&quot; alt=&quot;Edge of real and fake coins&quot;&gt;&lt;/p&gt;

&lt;p&gt;The main things that let me spot this coin was fake were
the inconsistent gap between the two metal segments,
the colour,
and the lack of detail in the engraving.&lt;/p&gt;

&lt;p&gt;We know from fake £1 coins that forgers can achieve a good level of detail
and colour match.
So it&amp;#39;s possible there are better fake £2 coins out there,
just good enough fakes that they haven&amp;#39;t been reported.&lt;/p&gt;

&lt;p&gt;I gather official surveys of the number of fake £1 coins in circulation involved
drawing a random sample of coins from banks and post offices
and using spectroscopy to check whether the metal composition matches genuine coins.&lt;/p&gt;

&lt;p&gt;According to &lt;a href=&quot;https://www.whatdotheyknow.com/request/counterfeit_coins&quot;&gt;FOIA&lt;/a&gt; &lt;a href=&quot;https://www.whatdotheyknow.com/request/proportion_of_counterfeit_coinag_2&quot;&gt;requests&lt;/a&gt;
as of December 2013 the Royal Mint only performs surveys of fake £1 coins.
Another request, dated &lt;a href=&quot;https://www.whatdotheyknow.com/request/surveying_of_counterfeits_in_ps2&quot;&gt;December 2014&lt;/a&gt;
is currently awaiting a response.&lt;/p&gt;

&lt;p&gt;For some other reports of fake £2 coins, see &lt;a href=&quot;http://www.coin-mech.co.uk/counterfeit-two-pound-coins.html&quot;&gt;here&lt;/a&gt;
and &lt;a href=&quot;http://24carat.co.uk/frame.php?url=faketwopoundcoin.html&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Kibana Log Searching 101</title>
   <link href="https://www.mjt.me.uk/posts/kibana-101/"/>
   <updated>2014-11-23T00:00:00+00:00</updated>
   <id>https://www.mjt.me.uk/posts/kibana-101</id>
   <content type="html">&lt;p&gt;So someone has just given you access to Kibana and you&amp;#39;re having trouble answering the kind of questions you could have answered easily with a sql- or grep-based system.&lt;/p&gt;

&lt;p&gt;Hopefully this cheat sheet will help get you started!&lt;/p&gt;

&lt;h2 id=&quot;how-do-i-do-a-basic-search&quot;&gt;How do I do a basic search?&lt;/h2&gt;

&lt;p&gt;The &amp;#39;query&amp;#39; box works a bit Google: unstructured text search, with some special commands, and if you get the command syntax wrong it just does an unstructured text search.&lt;/p&gt;

&lt;p&gt;Unlike Google, by default it searches for entries containing &lt;em&gt;any&lt;/em&gt; of your search terms, and it considers hyphen a &lt;em&gt;delimiter&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Example queries:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;addressregistry&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;solution-addressregistry&lt;/code&gt; &amp;lt;-- Finds entries containing &amp;#39;solution&amp;#39; or &amp;#39;addressregistry&amp;#39;&lt;/p&gt;

&lt;h2 id=&quot;what-if-i-want-to-search-for-a-string-literal&quot;&gt;What if I want to search for a string literal?&lt;/h2&gt;

&lt;p&gt;Double quotes.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;#39;asdf-addressregistry&amp;#39;&lt;/code&gt; &amp;lt;-- &lt;strong&gt;Wrong,&lt;/strong&gt; single quotes get ignored - this searches for &amp;#39;asdf&amp;#39; or &amp;#39;addressregistry&amp;#39;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;quot;geo-address-registry&amp;quot;&lt;/code&gt; &amp;lt;-- That&amp;#39;s how you quote things properly&lt;/p&gt;

&lt;h2 id=&quot;so-it-doesn-39-t-tell-you-if-you-39-ve-got-the-syntax-wrong&quot;&gt;So it doesn&amp;#39;t tell you if you&amp;#39;ve got the syntax wrong?&lt;/h2&gt;

&lt;p&gt;I know, right? Pretty much the opposite of SQL. Takes some getting used to, and makes it harder to figure out through experimentation - hence this documentation!&lt;/p&gt;

&lt;h2 id=&quot;how-do-i-search-a-single-field&quot;&gt;How do I search a single field?&lt;/h2&gt;

&lt;p&gt;Field name, then a colon.&lt;/p&gt;

&lt;p&gt;Example:
&lt;code&gt;tags:&amp;quot;address-registry&amp;quot;&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&quot;what-about-searching-for-missing-or-present-fields&quot;&gt;What about searching for missing (or present) fields?&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;&lt;em&gt;exists&lt;/em&gt;:exception&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;em&gt;missing&lt;/em&gt;:message&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&quot;what-about-searching-for-several-things&quot;&gt;What about searching for several things?&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;&lt;em&gt;exists&lt;/em&gt;:exception AND tags:routing&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;em&gt;exists&lt;/em&gt;:exception AND routing&lt;/code&gt; &amp;lt;-- Second becomes free text search&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;em&gt;exists&lt;/em&gt;:exception AND ( tags:routing OR appID:geo )&lt;/code&gt; &amp;lt;-- This does what it looks like&lt;/p&gt;

&lt;p&gt;AND and OR are case-sensitive. Example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tags:routing AND kjrnglkjerghljkf&lt;/code&gt; &amp;lt;-- No results, no entry tagged routing also contains free text kjrnglkjerghljkf&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tags:routing and kjrnglkjerghljkf&lt;/code&gt; &amp;lt;-- &lt;strong&gt;Wrong,&lt;/strong&gt; this finds anything tagged routing, or with free text &amp;#39;and&amp;#39; or with free text kjrnglkjerghljkf&lt;/p&gt;

&lt;h2 id=&quot;so-is-it-it-all-case-sensitive-then&quot;&gt;So is it it all case-sensitive, then?&lt;/h2&gt;

&lt;p&gt;Text matching is case-insensitive, but field names and AND and OR are case insensitive.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tags:routing&lt;/code&gt; &amp;lt;-- Normal query&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tags:ROUTING&lt;/code&gt; &amp;lt;-- Matches the same thing (text match case insensitive)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Tags:routing&lt;/code&gt; &amp;lt;-- No results (field name case sensitive)&lt;/p&gt;

&lt;h2 id=&quot;why-doesn-39-t-appid-geo-addressregistry-v1-do-what-i-expect&quot;&gt;Why doesn&amp;#39;t appID:geo-addressregistry-v1 do what I expect?&lt;/h2&gt;

&lt;p&gt;The hyphens are delimiters. It&amp;#39;s searching for anything with appID containing geo, or free text containing addressregistry or v1.&lt;/p&gt;

&lt;h2 id=&quot;well-then-why-doesn-39-t-appid-quot-geo-address-registry-v1-quot-do-what-i-expect&quot;&gt;Well then, why doesn&amp;#39;t appId:&amp;quot;geo-address-registry-v1&amp;quot; do what I expect?&lt;/h2&gt;

&lt;p&gt;Check the capitalisation of that tag. Are you looking for appId when you should be looking for appID?&lt;/p&gt;

&lt;h2 id=&quot;well-then-why-doesn-39-t-appid-quot-geo-addressregistry-v1-quot-do-what-i-expect&quot;&gt;Well then, why doesn&amp;#39;t appID:&amp;quot;geo-addressregistry-v1&amp;quot; do what I expect?&lt;/h2&gt;

&lt;p&gt;Because you&amp;#39;re missing a hyphen. Try &lt;code&gt;appID:&amp;quot;geo-address-registry-v1&amp;quot;&lt;/code&gt; instead.&lt;/p&gt;

&lt;h2 id=&quot;so-what-are-these-filter-things&quot;&gt;So what are these filter things?&lt;/h2&gt;

&lt;p&gt;They&amp;#39;re like query strings, except the results get cached. I think. And you can toggle them and add them automatically from that magnifying glass symbol! Pretty weird design if you ask me.&lt;/p&gt;

&lt;h2 id=&quot;what-39-s-with-the-39-save-39-and-39-apply-39-buttons&quot;&gt;What&amp;#39;s with the &amp;#39;save&amp;#39; and &amp;#39;apply&amp;#39; buttons?&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/kibana/filter.png&quot; alt=&quot;Kibana filter box screenshot&quot;&gt;&lt;/p&gt;

&lt;p&gt;The &amp;#39;apply&amp;#39; button saves the filter and updates your results.&lt;/p&gt;

&lt;p&gt;The &amp;#39;save&amp;#39; button saves the filter but &lt;strong&gt;doesn&amp;#39;t update the results&lt;/strong&gt;. I&amp;#39;m not sure why you&amp;#39;d want to do that, but it&amp;#39;s there if you do.&lt;/p&gt;

&lt;h2 id=&quot;how-do-you-find-the-distinct-values-for-a-field&quot;&gt;How do you find the distinct values for a field?&lt;/h2&gt;

&lt;p&gt;This can be done, but it&amp;#39;s a bit odd. First you want to add an panel to a dashboard row:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/kibana/add-to-panel.png&quot; alt=&quot;Adding to dashboard panel&quot;&gt;&lt;/p&gt;

&lt;p&gt;Set the type to &amp;#39;terms&amp;#39;, the &amp;#39;field&amp;#39; to whatever field you want the distinct values of, and the length to some big number.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/kibana/terms-panel.png&quot; alt=&quot;Configuring terms panel&quot;&gt;&lt;/p&gt;

&lt;p&gt;You probably want the style to be &amp;#39;table&amp;#39; - easy to experiment with it though.&lt;/p&gt;

&lt;h2 id=&quot;i-deleted-the-only-filter-and-now-it-39-s-telling-me-quot-no-time-filter-timestamped-indices-are-configured-without-a-failover-waiting-for-time-filter-quot&quot;&gt;I deleted the only filter and now it&amp;#39;s telling me &amp;quot;No time filter Timestamped indices are configured without a failover. Waiting for time filter.&amp;quot;&lt;/h2&gt;

&lt;p&gt;I think the first index on the database is on time or something. Anyway, you have to add it back in, you can do that with this dropdown:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/kibana/time-range-dropdown.png&quot; alt=&quot;Time range dropdown&quot;&gt;&lt;/p&gt;

&lt;h2 id=&quot;how-do-i-find-the-log-lines-immediately-before-and-after-a-given-line-as-one-might-with-grep-c20&quot;&gt;How do I find the log lines immediately before and after a given line, as one might with grep -c20 ?&lt;/h2&gt;

&lt;p&gt;Unfortunately &lt;a href=&quot;https://github.com/elasticsearch/kibana/issues/275&quot;&gt;this isn&amp;#39;t supported&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;how-do-i-share-a-query-with-my-colleagues-by-e-mail&quot;&gt;How do I share a query with my colleagues by e-mail?&lt;/h2&gt;

&lt;p&gt;There&amp;#39;s a &amp;#39;share button&amp;#39; which will generate a permalink:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/kibana/share.png&quot; alt=&quot;Share button&quot;&gt;&lt;/p&gt;

&lt;p&gt;Note that if your query includes &amp;#39;the last hour&amp;#39; or similar, in an hour the results will have all changed.&lt;/p&gt;

&lt;h2 id=&quot;what-about-a-permalink-to-a-log-line&quot;&gt;What about a permalink to a log line?&lt;/h2&gt;

&lt;p&gt;This feature &lt;a href=&quot;https://github.com/elasticsearch/kibana/issues/717&quot;&gt;might be in a future version&lt;/a&gt; - in the meantime you can do this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a filter on _id so your query returns one line.&lt;/li&gt;
&lt;li&gt;Mess with the timestamp so your link works when your line exits the &amp;#39;last 30 minutes&amp;#39; window or whatever you have selected.&lt;/li&gt;
&lt;li&gt;Then e-mail a permalink.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not the most elegant method, obviously.&lt;/p&gt;

&lt;h2 id=&quot;what-if-i-want-to-copy-a-query-between-prod-and-dev-or-similar&quot;&gt;What if I want to copy a query between Prod and Dev or similar?&lt;/h2&gt;

&lt;p&gt;Permalinks are just references to a database entry, not a complete encoding of the dashboard. Export the schema as JSON and import it somewhere else like so:&lt;/p&gt;

&lt;p&gt;​&lt;img src=&quot;/assets/images/kibana/json-export.png&quot; alt=&quot;JSON export&quot;&gt;&lt;/p&gt;

&lt;h2 id=&quot;why-is-googling-for-kibana-query-strings-so-hard&quot;&gt;Why is googling for kibana query strings so hard?&lt;/h2&gt;

&lt;p&gt;Kibana is backed by ElasticSearch so sometimes google helpfully adds elasticsearch query documentation to your search for kibana query documentation. But ElasticSearch has a bunch of features that don&amp;#39;t work in the kibana query box.&lt;/p&gt;

&lt;p&gt;For example, when you look at &lt;a href=&quot;http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html#query-string-syntax&quot;&gt;this documentation&lt;/a&gt; the one-liners at the bookmarked point in the page will work - but if you scroll up to the JSON stuff, that won&amp;#39;t work in the kibana query box.&lt;/p&gt;

&lt;p&gt;You may have better results searching for &amp;#39;lucene query syntax&amp;#39; which is the syntax used by the kibana &amp;#39;query&amp;#39; box&lt;/p&gt;

&lt;h2 id=&quot;how-do-i-get-a-graph-with-multiple-lines&quot;&gt;How do I get a graph with multiple lines?&lt;/h2&gt;

&lt;p&gt;So it turns out the green dot is a button!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/kibana/green-dot.png&quot; alt=&quot;Green Dot&quot;&gt;
​&lt;/p&gt;

&lt;p&gt;If you set the type to &amp;#39;topN&amp;#39; and the field to whatever you want to chart, it&amp;#39;ll chart the frequency of the most frequent N values:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/kibana/topn.png&quot; alt=&quot;Top N query&quot;&gt;&lt;/p&gt;

&lt;p&gt;​
You can also add multiple queries by using the &amp;#39;+&amp;#39; to the right of the query box&lt;/p&gt;

&lt;p&gt;​&lt;img src=&quot;/assets/images/kibana/multiple-queries.png&quot; alt=&quot;Adding an extra query&quot;&gt;
​
​&lt;img src=&quot;/assets/images/kibana/multiquery.png&quot; alt=&quot;Multiple queries&quot;&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately this graph seems to count hyphenated values multiple times (e.g. &amp;#39;address-registry&amp;#39; counts for both &amp;#39;address&amp;#39; and &amp;#39;registry&amp;#39;) them&amp;#39;s the breaks.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Dirty Pcbs first trial board</title>
   <link href="https://www.mjt.me.uk/posts/dirtypcbs/"/>
   <updated>2014-05-14T00:00:00+01:00</updated>
   <id>https://www.mjt.me.uk/posts/dirtypcbs</id>
   <content type="html">&lt;p&gt;After I saw &lt;a href=&quot;http://dirtypcbs.com/&quot;&gt;Dirty PCBs&lt;/a&gt; on HN I decided to place a test order.&lt;/p&gt;

&lt;p&gt;I chose a 50mm x 50mm board and paid $12.&lt;/p&gt;

&lt;p&gt;I placed the order on the 13th April; the boards were reported as shipped on the 30th April, and they reached me (in the UK) the 14th May. Dirty boards tell me there was a hiccup at the board house, as they moved locations, so their normal turnaround time may be less.&lt;/p&gt;

&lt;p&gt;The customs value was $5, below the threshold to be charged duty and VAT. That was good, because the Royal Mail would have ripped me off with an £8 handling fee if there had been tax to pay.&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s the design I sent to be manufactured - yes, I could have spent more time getting the layout nicer, but this is just for testing:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/dirtypcbs/dirtypcbs_design.png&quot; alt=&quot;The design sent to the board house.&quot;&gt;&lt;/p&gt;

&lt;p&gt;And here&amp;#39;s the board I got back:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/dirtypcbs/dirtypcbs_top.jpg&quot; alt=&quot;Top side of one board&quot;&gt;
&lt;img src=&quot;/assets/images/dirtypcbs/dirtypcbs_bottom.jpg&quot; alt=&quot;Bottom side of board&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/dirtypcbs/six_boards_small.jpg&quot; alt=&quot;Six boards, checkerboard up/down&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/dirtypcbs/six_boards.jpg&quot;&gt;For a more detailed scan, see here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/dirtypcbs/board_detail.jpg&quot; alt=&quot;Detail of one board&quot;&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the solder resist between the pins of the TQFP (U1) is a bit lacking - although that might be partly due to my shitty footprint drawing skills. &lt;strong&gt;Edit:&lt;/strong&gt; Confirmed as my mistake - see below.&lt;/p&gt;

&lt;p&gt;The drills and silkscreening could be aligned more precisely - the last image above shows one of the worst boards, most of the ten are tidier than that. Even the worst board is within the advertised tolerances.&lt;/p&gt;

&lt;p&gt;All things considered, the price is good, it&amp;#39;s a lot less hassle than setting up tubs of ferric chloride in my bedroom, and more affordable for prototypes than Eurocircuits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Edit:&lt;/strong&gt; It turns out there&amp;#39;s a setting called &amp;#39;solder mask expansion&amp;#39; where holes for pads in the solder mask are made slightly larger, in case the solder mask is slightly misaligned. I had this set to 0.1mm - and given that my pads were 0.5mm wide and 0.8mm apart, giving a 0.3mm gap between pads, by applying a 0.1mm expansion on both sides, the solder mask was reduced to 0.1mm wide.&lt;/p&gt;

&lt;p&gt;I ordered another board, and this time I reduced the solder mask expansion from 0.1mm to 0.05mm, and reduced the pad width from 0.5mm to 0.4mm (the datasheet lists the pin sizes as 0.37mm nominal, 0.45mm max). I also made the pads longer, as I realised I&amp;#39;d made them so short the pins of the chip completely covered them! Before and after footprints:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/dirtypcbs/fixed-footprint-tqfp32.png&quot; alt=&quot;Fixed footprint for TQFP32&quot;&gt;&lt;/p&gt;

&lt;p&gt;The red area here is the pad itself, and the purple border is the solder mask expansion - as you can see the gaps between pads are looking a lot healthier now!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Amazon collection locker</title>
   <link href="https://www.mjt.me.uk/posts/amazon-collection-locker/"/>
   <updated>2014-04-06T00:00:00+01:00</updated>
   <id>https://www.mjt.me.uk/posts/amazon-collection-locker</id>
   <content type="html">&lt;p&gt;I tried collecting some stuff from an Amazon locker, to see what the customer experience is like.&lt;/p&gt;

&lt;p&gt;The locker address is presented as a normal delivery address in your address book.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/amazon-click-collect/amazon-locker-address.png&quot; alt=&quot;Locker delivery address&quot;&gt;&lt;/p&gt;

&lt;p&gt;When your item is available, you get an SMS: &amp;quot;Hello. Your parcel with (Item Name Which May Be Truncated) was delivered to Amazon Locker. Use pickup code: ABCD1A for this parcel&amp;quot;&lt;/p&gt;

&lt;p&gt;The message arrived quite quickly - I assume the locker triggers sending the SMS when the parcel is deposited, rather than the courier company triggering it when the driver marks the item as delivered.&lt;/p&gt;

&lt;p&gt;This locker is indoors. The power and 3G connections can be seen at the top.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/amazon-click-collect/IMAG0733.jpg&quot; alt=&quot;Photo of entire locker&quot;&gt;&lt;/p&gt;

&lt;p&gt;There&amp;#39;s a camera above the screen. Presumably this monitors customers picking up goods and drivers dropping off goods.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/amazon-click-collect/IMAG0745.jpg&quot; alt=&quot;Camera above screen&quot;&gt;&lt;/p&gt;

&lt;p&gt;A customer service contact number is marked on the lockers.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/amazon-click-collect/IMAG0744.jpg&quot; alt=&quot;Photograph of click and collect locker&quot;&gt;&lt;/p&gt;

&lt;p&gt;When no-one&amp;#39;s picking things up, the screen shows information on locker delivery:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/amazon-click-collect/IMAG0734.jpg&quot; alt=&quot;Touch screen&quot;&gt;&lt;/p&gt;

&lt;p&gt;An access code is sent by e-mail / SMS when your item is in the locker. On the bottom left is a button marked &amp;#39;carrier entry&amp;#39; which is presumably what the delivery drivers use to add items to the locker.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/amazon-click-collect/IMAG0735.jpg&quot; alt=&quot;Screen for code entry&quot;&gt;&lt;/p&gt;

&lt;p&gt;The code unlocks the locker like so:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/amazon-click-collect/IMAG0736.jpg&quot; alt=&quot;Screen for door opening&quot;&gt;
&lt;img src=&quot;/assets/images/amazon-click-collect/IMAG0738.jpg&quot; alt=&quot;Locker opened&quot;&gt;&lt;/p&gt;

&lt;p&gt;The locking mechanism looks like a rotary latch lock.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/amazon-click-collect/IMAG0740.jpg&quot; alt=&quot;Lock mechanism bold&quot;&gt;
&lt;img src=&quot;/assets/images/amazon-click-collect/rotary-latch-lock-1.jpg&quot; alt=&quot;Lock mechanism latch&quot;&gt;
&lt;img src=&quot;/assets/images/amazon-click-collect/rotary-latch-lock-2.jpg&quot; alt=&quot;Lock mechanism latch&quot;&gt;
&lt;img src=&quot;/assets/images/amazon-click-collect/IMAG0741.jpg&quot; alt=&quot;Door retention chain&quot;&gt;&lt;/p&gt;

&lt;p&gt;I had no need for this barcode scanner - presumably it&amp;#39;s used by the driver dropping packages off:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/amazon-click-collect/IMAG0743.jpg&quot; alt=&quot;Photograph of click and collect locker&quot;&gt;&lt;/p&gt;

&lt;p&gt;The parcel looks like this - my guess is the driver presents the &amp;#39;locker bar code&amp;#39; to the locker scanner and it opens an appropriate locker for the package.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/amazon-click-collect/IMAG0746.jpg&quot; alt=&quot;Photograph of click and collect locker&quot;&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Getting jd-gui to work on Ubuntu 13.10 x86_64</title>
   <link href="https://www.mjt.me.uk/posts/getting-jd-gui-to-work-on-ubuntu-13.10/"/>
   <updated>2014-02-22T00:00:00+00:00</updated>
   <id>https://www.mjt.me.uk/posts/getting-jd-gui-to-work-on-ubuntu-13.10</id>
   <content type="html">&lt;p&gt;So you&amp;#39;ve just downloaded the latest version of &lt;a href=&quot;http://jd.benow.ca/&quot;&gt;jd-gui&lt;/a&gt; for linux but it doesn&amp;#39;t start.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLDR:&lt;/strong&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;sudo apt-get install libgtk2.0-0:i386 libxxf86vm1:i386 libsm6:i386 lib32stdc++6
&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;More details:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s the process I went through:
&lt;pre&gt;
$ ./jd-gui 
./jd-gui: error while loading shared libraries: libgtk-x11-2.0.so.0: cannot open shared object file: No such file or directory
$ sudo apt-get install libgtk2.0-0:i386
$ ./jd-gui 
./jd-gui: error while loading shared libraries: libXxf86vm.so.1: cannot open shared object file: No such file or directory
$ sudo apt-get install libxxf86vm1:i386
$ ./jd-gui 
./jd-gui: error while loading shared libraries: libSM.so.6: cannot open shared object file: No such file or directory
$ sudo apt-get install libsm6:i386
$ ./jd-gui 
./jd-gui: error while loading shared libraries: libstdc++.so.6: cannot open shared object file: No such file or directory
$ sudo apt-get install lib32stdc++6
$ ./jd-gui 
Gtk-Message: Failed to load module &amp;quot;overlay-scrollbar&amp;quot;
Gtk-Message: Failed to load module &amp;quot;unity-gtk-module&amp;quot;
(jd-gui:4746): Gtk-WARNING **: Unable to locate theme engine in module_path: &amp;quot;murrine&amp;quot;,
...And it works!
&lt;/pre&gt;&lt;/p&gt;

&lt;p&gt;Happy decompiling!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Sending breaks to serial devices from the terminal, using termios</title>
   <link href="https://www.mjt.me.uk/posts/send-break-to-serial-rs232-device-from-terminal-tcsendbrake-termios/"/>
   <updated>2014-01-04T00:00:00+00:00</updated>
   <id>https://www.mjt.me.uk/posts/send-break-to-serial-rs232-device-from-terminal-tcsendbrake-termios</id>
   <content type="html">&lt;p&gt;I&amp;#39;m playing around with an mbed LPC1768 for a project I&amp;#39;m working on. When you upload a new binary to the LPC1768 you have to perform a reset for it to run the updated binary; you can do this with a reset button on the board, or by triggering a soft reset by sending a break signal to a virtual serial port. To speed up my compile-upload-test cycle I wanted to be able to do this from the terminal, on OS X.&lt;/p&gt;

&lt;p&gt;You can send a break manually using screen, but I wanted something noninteractive so I could trigger a compile-upload-test with a single command. Turns out it&amp;#39;s fairly simple in C:&lt;/p&gt;

&lt;div&gt;&lt;script src=&quot;https://gist.github.com/michaeltandy/8250371.js&quot;&gt; &lt;/script&gt;&lt;/div&gt;

&lt;p&gt;Compile with &lt;code&gt;gcc -o sendbreak sendbreak.c&lt;/code&gt; then run with &lt;code&gt;./sendbreak /dev/tty.usbmodem622&lt;/code&gt; where /dev/tty.usbmodem622 is the device you want to send the break to.&lt;/p&gt;

&lt;p&gt;Don&amp;#39;t have gcc? I think for me it came with xcode.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Barcode reader test cases</title>
   <link href="https://www.mjt.me.uk/posts/barcode-reader-test-cases/"/>
   <updated>2013-12-01T00:00:00+00:00</updated>
   <id>https://www.mjt.me.uk/posts/barcode-reader-test-cases</id>
   <content type="html">&lt;p&gt;I&amp;#39;ve had an interest in barcodes and image processing for some time, and as a side project some time ago I put together a software barcode reader. One of the things I did for that project was start collecting photos of barcodes that didn&amp;#39;t scan well - either to use the images for my unit tests, or to order the products for physical tests.&lt;/p&gt;

&lt;p&gt;You can use these photos of degenerate barcodes to test your own barcode scanning software, or to order the products yourself for testing. If you want the images at a higher resolution, drop me an e-mail.&lt;/p&gt;

&lt;h2 id=&quot;low-constrast-barcodes&quot;&gt;Low constrast barcodes&lt;/h2&gt;

&lt;p&gt;I don&amp;#39;t know if these ones are just low contrast, or if the blue causes problems for red-laser scanners.
&lt;img src=&quot;/assets/images/barcodes/contrast1.jpg&quot; alt=&quot;Example barcode&quot;&gt;
&lt;img src=&quot;/assets/images/barcodes/contrast2.jpg&quot; alt=&quot;Example barcode&quot;&gt;
&lt;img src=&quot;/assets/images/barcodes/contrast3.jpg&quot; alt=&quot;Example barcode&quot;&gt;&lt;/p&gt;

&lt;p&gt;Seriously?
&lt;img src=&quot;/assets/images/barcodes/contrast4.jpg&quot; alt=&quot;Example barcode&quot;&gt;&lt;/p&gt;

&lt;p&gt;Product packaging in grey:
&lt;img src=&quot;/assets/images/barcodes/contrast5.jpg&quot; alt=&quot;Example barcode&quot;&gt;&lt;/p&gt;

&lt;h2 id=&quot;low-quality-printing&quot;&gt;Low quality printing&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/barcodes/printquality1.jpg&quot; alt=&quot;Example barcode&quot;&gt;
&lt;img src=&quot;/assets/images/barcodes/printquality2.jpg&quot; alt=&quot;Example barcode&quot;&gt;
&lt;img src=&quot;/assets/images/barcodes/printquality3.jpg&quot; alt=&quot;Example barcode&quot;&gt;&lt;/p&gt;

&lt;h2 id=&quot;barcodes-on-flexible-material&quot;&gt;Barcodes on flexible material&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/barcodes/flexible1.jpg&quot; alt=&quot;Example barcode&quot;&gt;
&lt;img src=&quot;/assets/images/barcodes/flexible2.jpg&quot; alt=&quot;Example barcode&quot;&gt;
Had to stretch this one out to get a scan:
&lt;img src=&quot;/assets/images/barcodes/flexible3.jpg&quot; alt=&quot;Example barcode&quot;&gt;
&lt;img src=&quot;/assets/images/barcodes/flexible4.jpg&quot; alt=&quot;Example barcode&quot;&gt;
&lt;img src=&quot;/assets/images/barcodes/flexible5.jpg&quot; alt=&quot;Example barcode&quot;&gt;&lt;/p&gt;

&lt;h2 id=&quot;barcodes-on-transparent-material&quot;&gt;Barcodes on transparent material&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/barcodes/transparent1.jpg&quot; alt=&quot;Example barcode&quot;&gt;
&lt;img src=&quot;/assets/images/barcodes/transparent2.jpg&quot; alt=&quot;Example barcode&quot;&gt;
&lt;img src=&quot;/assets/images/barcodes/transparent3.jpg&quot; alt=&quot;Example barcode&quot;&gt;&lt;/p&gt;

&lt;h2 id=&quot;size-amp-detail&quot;&gt;Size &amp;amp; Detail&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/barcodes/sizedetail1.jpg&quot; alt=&quot;Example barcode&quot;&gt;
Which is a dark band, which is a light band?
&lt;img src=&quot;/assets/images/barcodes/sizedetail2.jpg&quot; alt=&quot;Example barcode&quot;&gt;&lt;/p&gt;

&lt;h2 id=&quot;bad-quiet-zone&quot;&gt;Bad quiet zone&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/barcodes/quietzone1.jpg&quot; alt=&quot;Example barcode&quot;&gt;
&lt;img src=&quot;/assets/images/barcodes/quietzone2.jpg&quot; alt=&quot;Example barcode&quot;&gt;&lt;/p&gt;

&lt;h2 id=&quot;reflective-packaging&quot;&gt;Reflective packaging&lt;/h2&gt;

&lt;p&gt;Difficult to see in the photo but this was hard to scan with a presentation scanner:
&lt;img src=&quot;/assets/images/barcodes/shiny1.jpg&quot; alt=&quot;Example barcode&quot;&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Falsehoods programmers believe about addresses</title>
   <link href="https://www.mjt.me.uk/posts/falsehoods-programmers-believe-about-addresses/"/>
   <updated>2013-05-29T00:00:00+01:00</updated>
   <id>https://www.mjt.me.uk/posts/falsehoods-programmers-believe-about-addresses</id>
   <content type="html">&lt;p&gt;Perhaps you&amp;#39;ve read posts like &lt;a href=&quot;http://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/&quot;&gt;Falsehoods Programmers Believe About Names&lt;/a&gt;
and &lt;a href=&quot;http://infiniteundo.com/post/25326999628/falsehoods-programmers-believe-about-time&quot;&gt;Falsehoods programmers believe about time&lt;/a&gt;.
Maybe you&amp;#39;ve also read &lt;a href=&quot;http://wiesmann.codiferes.net/wordpress/?p=15187&amp;amp;lang=en&quot;&gt;Falsehoods programmers believe about geography&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Addressing is a fertile ground for incorrect assumptions, because everyone&amp;#39;s used to dealing with addresses and 99% of the time they seem so simple.
Below are some incorrect assumptions I&amp;#39;ve seen made, or made myself, or had reported to me.
(If you want to look up an address for a UK postcode or vice-versa to confirm what I&amp;#39;m telling you, try the &lt;a href=&quot;http://www.royalmail.com/postcode-finder/&quot;&gt;Royal Mail Postcode Finder&lt;/a&gt;)&lt;/p&gt;

&lt;!-- Composition of building numbers --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;An address will start with, or at least include, a building number.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Counterexample: Royal Opera House, Covent Garden, London, WC2E 9DD, United Kingdom.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;When there is a building number, it will be all-numeric.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Counterexample: 1A Egmont Road, Middlesbrough, TS4 2HT&lt;/p&gt;

&lt;p&gt;4-5 Bonhill Street, London, EC2A 4BX&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No buildings are numbered zero&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Counterexample: 0 Egmont Road, Middlesbrough, TS4 2HT&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Well, at the very least no buildings have negative numbers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Guy Chisholm provided this counterexample: Minusone Priory Road, Newbury, RG14 7QS&lt;/p&gt;

&lt;p&gt;(none of the databases I&amp;#39;ve checked render this as -1)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;We can put those funny numbers into the building name field, as no buildings have both a name and a funny number&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Counterexample: Idas Court, 4-6 Princes Road, Hull, HU5 2RD&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;When there&amp;#39;s a building name, there won&amp;#39;t be a building number (or vice-versa)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Counterexample: Flat 1.4, Ziggurat Building, 60-66 Saffron Hill, London, EC1N 8QX, United Kingdom&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A building number will only be used once per street&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The difference between 50 Ammanford Road, Tycroes, Ammanford, SA18 3QJ and 50 Ammanford Road, Llandybie, Ammanford, SA18 3YF is about 4 miles (&lt;a href=&quot;https://maps.google.co.uk/maps?q=SA18+3QJ+to+SA18+3YF&quot;&gt;Google Maps&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;When there&amp;#39;s line with a number in an address, it&amp;#39;s the building number.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Counterexample: Flat 18, Da Vinci House, 44 Saffron Hill, London, EC1N 8FH, United Kingdom&lt;/p&gt;

&lt;p&gt;You also get suite numbers, floor numbers, unit numbers, and organisations with numbers in their names.&lt;/p&gt;

&lt;p&gt;Adrien Piérard contributes an address from Japan with fifteen digits in six separate numbers (five if you count the zip code as a single number). The format is: 980-0804 (zip code), Miyagi-ken (prefecture) Sendai-shi (city) Aoba-ku (ward) Kokubuncho (district) 4-10-20 (sub-district-number block-number lot-number) Sendai (building name) 401 (flat number).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;OK, the first line starting with a number then&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Counterexample: 3 Store, 311-318 High Holborn, London, WC1V 7BN&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A building will only have one number&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Benton Lam offers this address from the Hong Kong Special Administrative Region - it has both a number on its road (14) and in its group of buildings (3): 15/F, Cityplaza 3, 14 TaiKoo Wan Road, Island East, HKSAR&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The number of buildings is the difference between the highest and lowest building numbers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tibor Schütz points out building numbers may be skipped - for example, on a street where even-numbered buildings are on one side, odd numbers on the other; multiple buildings sharing the same number (such as where a new house has been built) and buildings with more than one number.&lt;/p&gt;

&lt;p&gt;Cyrille Chépélov and Sami Lehtinen tell me in Antibes, France and rural Finland some buildings are numbered based on the distance from the start of the road - such as Longroad 65 for the building 750m from the start of longroad.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;If the addresses on the left of the road are even, the addresses on the right must be odd&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cyrille Chépélov points out that in places, &lt;a href=&quot;https://maps.google.fr/maps?q=48.857415,2.467167&quot;&gt;Boulevard Théophile Sueur, Montreuil, Seine-Saint-Denis, France&lt;/a&gt; has evens-only on both sides. The two sides are also in different cities and Départements.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A building name won&amp;#39;t also be a number&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ben Tilly reports on Ten Post Office Sq, Boston MA 02109 USA - which is not, reportedly, the same as 10 Post Office Sq, Boston MA 02109 USA.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Well, at least you can omit leading zeros&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Shaun Crampton reports living at 101 Alma St, Apartment 001, Palo Alto - where apartments 1 and 001 were on different floors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A street with a building A will not also have a building Alpha&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Douglas Perreault reports he lived in a block within a condo association; it was a large association, with blocks A through Z then Alpha, Beta, Gamma, Delta, and Theta. Mail and deliveries were often misrouted from block Alpha to block A and vice-versa. His address at the time was: 14100 N 46th St., Alpha 39, Tampa, FL 33613&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- Composition of street names --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A street name won&amp;#39;t include a number&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;8 Seven Gardens Burgh, WOODBRIDGE, IP13 6SU (pointed out by Raphael Mankin)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;OK, but numbers in street names are expressed as words, not digits&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Jan Jongboom reports streets can be numbered in the Netherlands - for example, Plein 1944 in Nijmegen.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;When there&amp;#39;s a numbered street and a house number, there will be a separator between them&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Another from Jan Jongboom: Gondel 2695, Lelystad, means area Gondel, street 26, number 95&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Street names always end in descriptors like &amp;#39;street&amp;#39;, &amp;#39;avenue&amp;#39;, &amp;#39;drive&amp;#39;, &amp;#39;square&amp;#39;, &amp;#39;hill&amp;#39; or &amp;#39;view&amp;#39;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They don&amp;#39;t always - for example: Piccadilly, London, W1J 9PN&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;OK, but when they do have a descriptor there will only be one&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A street name can be entirely descriptors: 17 Hill Street, London, W1J 5LJ or &lt;a href=&quot;https://en.wikipedia.org/wiki/Avenue_Road&quot;&gt;Avenue Road, Toronto, Ontario&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;OK, but when they do have a descriptor it will be at the end&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;French addresses use prefix descriptors like &amp;#39;rue&amp;#39;, &amp;#39;avenue&amp;#39;, &amp;#39;place&amp;#39; and &amp;#39;allee&amp;#39;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;OK, but if there&amp;#39;s a descriptor it&amp;#39;ll be at the start or end of the street name.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Or the middle, like 3 Bishops Square Business Park, Hatfield, AL10 9NA&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;OK, but at the very least you wouldn&amp;#39;t name a town Street&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://maps.google.co.uk/maps?q=Street,+Somerset&quot;&gt;Actually there&amp;#39;s a town called Street in Somerset, UK&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Street numbers (and building numbers) don&amp;#39;t contain fractions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Dan, Fred Kroon, David Underwood and Daniel Dickison submitted examples of fractional street numbers like &lt;a href=&quot;https://maps.google.com/maps?q=43rd%20%C2%BD%20st,%20Pittsburgh,%20PA&quot;&gt;43rd ½ St, Pittsburgh, PA&lt;/a&gt;, and of fractional building numbers. These can be written in unicode (43rd ½ St), as a fraction with a slash (43 1/2) or as a decimal (43.5)&lt;/p&gt;

&lt;p&gt;Gene Wirchenko reports a fractional building number: 1313 1/2 Railroad Ave Bellingham WA 98225-4729&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Street names don&amp;#39;t recurr in the same city&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://maps.google.co.uk/maps?q=from:W3+6LJ+to:W5+5DB+to:N8+7PB+to:SE25+6EP+to:E13+0AJ+to:E17+7LD+to:NW10+4LX+to:N1+9TR+to:E1+6PG+to:NW1+0JH+to:W14+8NL+to:SE13+6AD+to:SW19+5DX+to:E11+2AJ+to:SW19+2AE+to:E6+2HJ+&amp;amp;saddr=W3+6LJ&amp;amp;daddr=W5+5DB+to:N8+7PB+to:SE25+6EP+to:E13+0AJ+to:E17+7LD+to:NW10+4LX+to:N1+9TR+to:E1+6PG+to:NW1+0JH+to:W14+8NL+to:SE13+6AD+to:SW19+5DX+to:E11+2AJ+to:SW19+2AE+to:E6+2HJ&quot;&gt;Here&amp;#39;s a map of the following addresses:&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High Street, London, W3 6LJ&lt;/li&gt;
&lt;li&gt;High Street, London, W5 5DB&lt;/li&gt;
&lt;li&gt;High Street, London, N8 7PB&lt;/li&gt;
&lt;li&gt;High Street, London, SE25 6EP&lt;/li&gt;
&lt;li&gt;High Street, London, E13 0AJ&lt;/li&gt;
&lt;li&gt;High Street, London, E17 7LD&lt;/li&gt;
&lt;li&gt;High Street, London, NW10 4LX&lt;/li&gt;
&lt;li&gt;Islington High Street, London, N1 9TR&lt;/li&gt;
&lt;li&gt;Shoreditch High Street, London, E1 6PG&lt;/li&gt;
&lt;li&gt;Camden High Street, London, NW1 0JH&lt;/li&gt;
&lt;li&gt;Kensington High Street, London, W14 8NL&lt;/li&gt;
&lt;li&gt;Lewisham High Street, London, SE13 6AD&lt;/li&gt;
&lt;li&gt;High Street Wimbledon, London, SW19 5DX&lt;/li&gt;
&lt;li&gt;High Street Wanstead, London, E11 2AJ&lt;/li&gt;
&lt;li&gt;High Street Colliers Wood, London, SW19 2AE&lt;/li&gt;
&lt;li&gt;High Street North, London, E6 2HJ &lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;But street names don&amp;#39;t recurr in close proximity&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Julian Fleischer provides an example from Bocholt in Germany showing several roads in close proximity all called &lt;a href=&quot;https://maps.google.com/maps?q=51.853945,6.615334&quot;&gt;Up de Welle&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;An address will be comprised of road names&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Kirk Kerekes spent several years using an address of the form &amp;quot;2 mi N then 3 mi W of Jennings, OK 74038&amp;quot; which regularly got successful deliveries. Mike Riley used to mail the Very Large Array radio telescope at &amp;quot;50 miles (80 km) West of Socorro, New Mexico, USA&amp;quot;&lt;/p&gt;

&lt;p&gt;Sam pointed me to &lt;a href=&quot;http://www.menomoneefallsnow.com/news/99857214.html&quot;&gt;Menomonee Falls&lt;/a&gt; where houses are addressed using Milwaukee County&amp;#39;s grid system instead of house numbers - giving addresses like N88 W16541 Foobar St.&lt;/p&gt;

&lt;p&gt;Andy Monat sent the following address example, from a &lt;a href=&quot;http://ciapa.tulane.edu/uploads/1_EE_2012_Acceptance_Packet_INFORMATION-1340749206.pdf&quot;&gt;semester abroad program at Tulane University &lt;/a&gt;: CIAPA, 50 meters north of the Hypermas/Walmart of Curridabat, San Jose, Costa Rica. Adrien Piérard and Luke Allardyce point out street names are seldom used in Japan - instead, districts and blocks and lot numbers are used (more info on the &lt;a href=&quot;https://en.wikipedia.org/wiki/Japanese_addressing_system&quot;&gt;Wikipedia entry for the Japanese addressing system&lt;/a&gt;).  A &lt;a href=&quot;http://www.worldpress.org/Americas/592.cfm&quot;&gt;2002 World Press Review report&lt;/a&gt; gave this sample address: From where the Chinese restaurant used to be, two blocks down, half a block toward the lake, next door to the house where the yellow car is parked, Managua, Nicaragua. Shaun Crampton sent &lt;a href=&quot;https://vianica.com/nicaragua/practical-info/14-addresses.html&quot;&gt;an article with more details and examples of the Nicaraguan system&lt;/a&gt;. Stig Brautaset pointed out &lt;a href=&quot;http://www.bbc.co.uk/news/magazine-14806350&quot;&gt;a BBC article about post in Kabul&lt;/a&gt; gives this example: &amp;quot;Hamid Jaan, behind Darul-Aman palace&amp;quot;. Nathan Fellman reports similar addressing is used in Nicaragua and Costa Rica.&lt;/p&gt;

&lt;p&gt;Paul Puschmann and Tibor Schütz pointed out the city of &lt;a href=&quot;http://de.wikipedia.org/wiki/Quadratestadt&quot;&gt;Mannheim in Germany is sometimes called Quadratestadt (City of Squares)&lt;/a&gt; as the city centre is arranged in a grid, with blocks assigned a letter (along the north-south axis) and a number (along the east-west axis) then buildings numbered by block number. So an example address at numbers 6 to 13 on block R 5 would be: Institut für Deutsche Sprache, R 5, 6-13, D-68161 Mannheim &lt;/p&gt;

&lt;p&gt;Leoni Lubbinge gives an example of a South African address: Part 84, Strydfontein 306 JR, Pretoria which means the 84th plot of the farm Strydfontein 306 JR.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- Elements being present or absent --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A road will have a name&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Plenty of roads like driveways, onramps and the aisles of carparks don&amp;#39;t have names. Some roads in Japan also don&amp;#39;t have names, as &lt;a href=&quot;https://en.wikipedia.org/wiki/Japanese_addressing_system&quot;&gt;the prevalent addressing system works on districts, subdistricts, blocks, lots and lot numbers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Peter Kenway points out in America some homes are addressed as Rural Routes, where numbers are allocated to boxes on a route covering multiple roads. For example: Box 1234, R.R. 1, Winthrop, ME 04364.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A road will only have one name&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Many different roads, from Goswell Road in London to Regent Road in Edinburgh, make up the 410 mile &lt;a href=&quot;https://en.wikipedia.org/wiki/A1_road_%28Great_Britain%29&quot;&gt;A1&lt;/a&gt;. And while there may only be one &amp;quot;1 Goswell Road&amp;quot; and only one &amp;quot;1 Regent Road&amp;quot; there are multiple buildings numbered 1 on the road designated A1.&lt;/p&gt;

&lt;p&gt;Roads may also be named in multiple languages. For example, in Ireland roads may be named in both English and Irish&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Addresses will only have one street&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Royal Mail have what they call a &amp;#39;dependent street&amp;#39; - for example: 6 Elm Avenue, Runcorn Road, Birmingham, B12 8QX, United Kingdom (Runcorn Road is the street, Elm Avenue is the stubby &amp;#39;dependent street&amp;#39; and isn&amp;#39;t unique within the city. &lt;a href=&quot;http://maps.google.co.uk/maps?q=B12+8QX&quot;&gt;Google Maps&lt;/a&gt; )&lt;/p&gt;

&lt;p&gt;Another counterexample: Rogue Hair, 1 Hopton Parade, Streatham High Road, London, SW16 6EP (Streatham High Road is the street. Hopton Parade is a little row of shops on the road - &lt;a href=&quot;http://maps.google.co.uk/maps?q=SW16+6EP&quot;&gt;Google Maps&lt;/a&gt; )&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Addresses will have a street&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Royal Mail will deliver to certain premises by name, such as farms and cottages. Example: Oakland, Fairseat, Sevenoaks, TN15 7LT, United Kingdom (Fairseat is the town - this is actually on Vigo Road. &lt;a href=&quot;https://maps.google.co.uk/maps?q=TN15+7LT&quot;&gt;Google Maps&lt;/a&gt; )&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;An address will include a state&lt;/strong&gt; in the US sense.&lt;/p&gt;

&lt;p&gt;Counterexample: Any address in the United Kingdom.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Addresses will have something other than the organisation and city name.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Large recipients of mail are sometimes addressed by organisation alone - for example: Electoral Reform Society Ltd, London, N1 1RS, United Kingdom&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;An address will have a county&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Iain Parris and Naath both pointed out that, while many websites ask users for a county, not all countries use them in addressing. For example, &lt;a href=&quot;https://en.wikipedia.org/wiki/Postal_counties_of_the_United_Kingdom&quot;&gt;the Royal Mail stopped using postal counties in 1996&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Yves Daoust reports that in Belgium an address only requires a street, postcode and city; example: Boulevard Frère Orban, 27, 4000 Liège. Erik Engheim reports that in Norway Oslo is a By (city), Tettsted (urban area), Kommune (municipality) and Fylke (county) but it usually only appears once in a written address.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;An address require both a city and a country&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;jzwinck points out Singapore is a city-state, leading to addresses like Singapore, Singapore - or even Singapore, Singapore, Singapore if you demand a city, county and country.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;You can&amp;#39;t have two towns cities with the same name in the same country&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sure you can - for example the UK has &lt;a href=&quot;https://maps.google.co.uk/maps?q=from:PO30+1SS+to:+NP20+1FQ+to:TF10+7AN&quot;&gt;three towns called Newport.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Jan Jongboom reports from the Netherlands, where there are two cities called Eursinge - in the same province!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;OK, but those cities won&amp;#39;t have duplicate street names&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;10 High Street, Newport, PO30 1SS&lt;/li&gt;
&lt;li&gt;10 High Street, Newport, NP20 1FQ&lt;/li&gt;
&lt;li&gt;10 High Street, Newport, TF10 7AN&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;An address will have a postcode&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Richard Fletcher, Lee Hosty, Paul O&amp;#39;Nolan, Simon Diab, Tony Finn, Donal Maccarthy, mark lynch and Donovan all pointed out countries like the Republic of Ireland have addresses without postcodes, or only have postcodes in certain parts of the country. Danny Angus points out this is also the case in Hong Kong.&lt;/p&gt;

&lt;p&gt;Jessica Enders points out &lt;a href=&quot;http://www.aec.gov.au/enrol/send-form.htm&quot;&gt;the post-paid address of the AEC&lt;/a&gt;: Australian Electoral Commission, Reply Paid 9867, your capital city&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- Postal / zip codes --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The user will know their postal code/zip code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most users will, of course, but I&amp;#39;ve seen incorrect postcodes on corporate letterheads! Misreading handwritten postcodes seems like a common one.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A single postcode will be larger than a single building&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Although zip codes in the US usually cover very large areas, Anthony Elizondo points out some buildings have their own zip codes - like the Empire State Building (10118)&lt;/p&gt;

&lt;p&gt;In the UK, alphanumeric postcodes are typically much more precise than US zip codes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;OK, but you don&amp;#39;t get multiple postcodes per building&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Graham Lee points out DVLA Swansea (that&amp;#39;s the whole address), where different departments are identified by postcode: V5Cs are processed at SA99 1BA, driving licences at SA99 1AB and so on.&lt;/p&gt;

&lt;p&gt;Malcolm Gilbert points out this example, with five postcodes for five departments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;London Borough of Enfield, Civic Centre, Silver Street, ENFIELD, EN1 3ES&lt;/li&gt;
&lt;li&gt;Returning Officer, London Borough of Enfield, Civic Centre, Silver Street, ENFIELD, EN1 9SA&lt;/li&gt;
&lt;li&gt;Edmonton, London Borough of Enfield, Civic Centre, Silver Street, ENFIELD, EN1 9SB&lt;/li&gt;
&lt;li&gt;Enfield North, London Borough of Enfield, Civic Centre, Silver Street, ENFIELD, EN1 9SD&lt;/li&gt;
&lt;li&gt;Enfield Southgate, London Borough of Enfield, Civic Centre, Silver Street, ENFIELD, EN1 3ZW&lt;/li&gt;
&lt;li&gt;But the Enfield council website contact page lists their postcode as EN1 3XY - which the Royal Mail think is a &lt;a href=&quot;https://maps.google.co.uk/maps?q=EN1+3ES+to+EN1+3XY&amp;amp;saddr=EN1+3ES&amp;amp;daddr=EN1+3XY&quot;&gt;PO Box at the sorting office&lt;/a&gt;. &lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A single postcode will only cover a few tens of addresses / customers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Mostly this is reasonable in the UK, but there are certain exceptions. For example CV4 7AL is the postcode of the University of Warwick - one postcode for 6,000 students living on campus, and academics/administrators working on campus.&lt;/p&gt;

&lt;p&gt;Also, if your customers get things delivered to them when they&amp;#39;re on holiday, lots of customers may have the same holiday parks on their accounts.&lt;/p&gt;

&lt;p&gt;Some addresses correspond to &amp;#39;flexible office spaces&amp;#39; and organisations that offer PO Boxes that sound like fancy offices. The Royal Mail lists more than 90 organisations operating out of Tower 42, 25 Old Broad Street, London, EC2N 1HQ. Holiday parks and cottages may also appear on many customers&amp;#39; accounts.&lt;/p&gt;

&lt;p&gt;Victor Nicollet contributes the example of French postcode 75015, representing the XVth arrondissement of Paris, which covers over 230,000 people.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A zip code corresponds to a single city&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Mike Cohen reports zip code 33334 covers 3 cities: Oakland Park, Wilton Manors, and Fort Lauderdale, all in Florida.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Zip codes don&amp;#39;t start with a zero&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Some Brazilian zip codes do according to speeder, as do &lt;a href=&quot;https://en.wikipedia.org/wiki/Postal_codes_in_Israel&quot;&gt;Israeli postcodes for army units&lt;/a&gt;. Jessica Enders and Frank Malcolm pointed out postcodes in the Northern Territory of Australia start with 08; for example the &lt;a href=&quot;http://auspost.com.au/apps/postcode.html&quot;&gt;postcode for the city Darwin is 0800&lt;/a&gt;. Morsillo Lindsay, Thomas Norris and Jerry B. Altzman point out American addresses in the north east have zip codes starting with zero, for example Ten Post Office Sq, Boston MA 02109, USA; and some zip codes start with two zeros. Mikael Vejdemo-Johansson reports the zip code of Jena in Germany is 07737.&lt;/p&gt;

&lt;p&gt;Antti Vikman and Johan Myréen tell me all postcodes in Helsinki, the capital of Finland, all start with two zeroes. Some special codes even start with four zeroes (00002 HELSINKI). Andrew Jones reports the initial digits of French postcodes are the départements*, and may use a leading zero. Post addressed to 06130 Grasse is correctly delivered to the town in district 06, Alpes Maritimes - but post addressed to 6130 Grasse is first routed to department 61, Orne. klez reports Italian Codice di Avviamento Postale (CAP) numbers can have a leading zero.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Except Corsica - Cyrille Chépélov reports it&amp;#39;s split into départements 2A and 2B, but the Post Office kept the former single-number 20 (Ajaccio, 20000; Bastia, 20200)&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- Sanitizing for your database or similar --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Addresses will have a reasonable number of characters - less than 100, say.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not when organisation and department names can be included in addresses! For example: Department For Environment Food &amp;amp; Rural Affairs (D E F R A), State Veterinary Service, Animal Health Office, Hadrian House, Wavell Drive, Rosehill Industrial Estate, Carlisle, CA1 2TB, United Kingdom&lt;/p&gt;

&lt;p&gt;Another example: The Gynaecology Cancer Research Unit, Department of Obstetrics &amp;amp; Gynaecology, St. Bartholomews &amp;amp; The Royal School of Medicine &amp;amp; Dentistry, Charterhouse Square, London, EC1M 6GR, United Kingdom&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;But street names will be reasonably short - certainly less than 50 characters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Susanne Schmidt provides the longest street name in Germany: Bischöflich-Geistlicher-Rat-Josef-Zinnbauer-Straße in 84130 Dingolfing, Bavaria&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://grcdi.blogspot.de/2010/09/how-long-is-your-street-name-field.html&quot;&gt;Graham Rhind&lt;/a&gt; suggests this 89-character street name in Bihac, Bosnia: Aleja Alije Izetbegovića Prvig Predsjednika Predsjedništva Republika Bosna i Hercegovina&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Five lines and country will cover all cases.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You&amp;#39;ll need 8 lines and country to deliver to: GB Technical Services, Unit W7a, Warwick House, 18 Forge Lane, Minworth Industrial Park, Minworth, Sutton Coldfield, B76 1AH, United Kingdom&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Addresses don&amp;#39;t contain commas&lt;/strong&gt; (so I can replace newlines with commas then commas with newlines and get back to where I was)&lt;/p&gt;

&lt;p&gt;Addresses can contain organisation names, and organisation names can contain commas. For example: Society of College, National &amp;amp; University Libraries, 102 Euston Street, London, NW1 2HA&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;But they don&amp;#39;t contain commas, brackets, apostrophes, hyphens, ampersands, dots or exclamation marks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;St. Judes &amp;amp; St. Pauls C of E (Va) Primary School, 10 Kingsbury Road, London, N1 4AZ&lt;/p&gt;

&lt;p&gt;1 Acre View, &lt;a href=&quot;https://en.wikipedia.org/wiki/Bo%27ness&quot;&gt;Bo’ness&lt;/a&gt;, EH51 9RQ&lt;/p&gt;

&lt;p&gt;1 Highview Terrace, &lt;a href=&quot;https://en.wikipedia.org/wiki/Westward_Ho!&quot;&gt;Westward Ho!&lt;/a&gt;, Bideford, EX39 1AQ (exclamation mark is omitted in some databases)&lt;/p&gt;

&lt;p&gt;Flat 1.4, Ziggurat Building, 60-66 Saffron Hill, London, EC1N 8QX, United Kingdom&lt;/p&gt;

&lt;p&gt;Kirkland, Lane, Mathias &amp;amp; Perry, North Muskham Prebend Church Street, Southwell, NG25 0HQ&lt;/p&gt;

&lt;p&gt;Mark Wallace tells us The Hague in the Netherlands is has multiple official names, one of which is &lt;a href=&quot;https://en.wikipedia.org/wiki/%27s-Gravenhage&quot;&gt;&amp;#39;s-Gravenhage&lt;/a&gt; (not a plural, literally a city name starting apostrophe s and with a hyphen)&lt;/p&gt;

&lt;p&gt;Signposts for Station Road East, Grantham, NG31 6HX render it as &lt;a href=&quot;https://maps.google.com/maps?q=Station+Road,+Grantham,+United+Kingdom&amp;amp;hl=en&amp;amp;ll=52.906793,-0.637872&amp;amp;spn=0.010237,0.027874&amp;amp;sll=40.47265,-79.962286&amp;amp;sspn=0.012846,0.027874&amp;amp;oq=station+road+west,+grantham&amp;amp;hnear=Station+Rd,+Lincolnshire+NG32,+United+Kingdom&amp;amp;t=m&amp;amp;z=16&amp;amp;layer=c&amp;amp;cbll=52.906821,-0.637709&amp;amp;panoid=sQ5jaVbNDVFoAwkjgYRzWg&amp;amp;cbp=12,320.99,,0,23.07&quot;&gt;STATION ROAD (EAST)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;More generally, addresses can contain organisation names, and organisations can have names like Yahoo! with an exclamation mark. Legislation on company &lt;a href=&quot;http://www.legislation.gov.uk/uksi/2009/1085/schedule/1/made&quot;&gt;sets out the allowable characters&lt;/a&gt; for the UK and it permits company names including ! LTD (company 08209948); @ LTD (company 08209882); $ LTD (company 08209885) and % LTD (company 04487680) as well as a variety of other names I don&amp;#39;t have examples for as the companies house website won&amp;#39;t let me search for them.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- Database Validation --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;An address will exist in the country&amp;#39;s postal service&amp;#39;s database&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Simon Westcott points out databases are only released periodically, so it&amp;#39;s not unusual for new buildings to be omitted.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;An address in the country&amp;#39;s postal service&amp;#39;s database will exist&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Royal Mail and Ordnance Survey data can contain demolished buildings, and buildings currently under construction. The Royal Mail even have a database product called &lt;a href=&quot;http://www.royalmail.com/marketing-services/address-management-unit/address-data-products/not-yet-built/details&quot;&gt;Not Yet Built&lt;/a&gt;. Temporary postcodes can even be assigned to building sites!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The address from the postal service database is sufficient to deliver&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Christopher Allen points out that people in new blocks of flats and houseboats in boatyards sometimes need to prefix their official address with a boat name or flat number.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Every address can be expressed in a way that will pass all validators&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;XaspR8d must have been exasperated by the fact his road is variously known as &amp;quot;S Hwy X&amp;quot;, &amp;quot;Highway X&amp;quot; and &amp;quot;South County Rd X&amp;quot; - and related a story of being unable to buy a product as the only addresses that passed a vendor&amp;#39;s address validation wouldn&amp;#39;t pass his bank&amp;#39;s address validation and vice-versa.&lt;/p&gt;

&lt;p&gt;Jon Peterson lives in an apartment community that is divided into Quail Ridge Cir, Quail Ridge East Lane and Quail Ridge West Lane. Only the USPS and the city electric utility seem to recognize the &amp;quot;Lane&amp;quot;. Everyone else requires it be shortened to &amp;quot;Quail Rdg E&amp;quot; (or W) and reportedly when UPS turns a package over to the USPS it gets returned as undeliverable-no such address.&lt;/p&gt;

&lt;p&gt;Susannah Fleming lived on the road the Royal Mail call Top O&amp;#39;The Lane, Brindle, Chorley, PR6 8PA. She reports representations in different databases include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Top o&amp;#39; th&amp;#39; Lane&lt;/li&gt;
&lt;li&gt;Top o&amp;#39;th&amp;#39; Lane&lt;/li&gt;
&lt;li&gt;Top oth Lane&lt;/li&gt;
&lt;li&gt;Top o&amp;#39; the Lane&lt;/li&gt;
&lt;li&gt;Top of the Lane&lt;/li&gt;
&lt;li&gt;Workhouse Lane (a historical name of the road)&lt;/li&gt;
&lt;li&gt;Denham Lane (name of the road continuation)&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- Addresses remaining static --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Customers will have a fixed address with a fixed location&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A developer just a few seats from me recently brought a &lt;a href=&quot;https://en.wikipedia.org/wiki/Houseboat&quot;&gt;house boat&lt;/a&gt; with the intention of using it as her primary residence. Needless to say, boats can move - including between towns and even countries!&lt;/p&gt;

&lt;p&gt;fr0sty points out the &lt;a href=&quot;http://www.elections.il.gov/downloads/votinginformation/pdf/r-19.pdf&quot;&gt;State of Illinois catch-all approach to addresses&lt;/a&gt;: &amp;quot;IF YOU HAVE NO STREET ADDRESS, below describe your home: list the name of subdivision; cross streets; roads; landmarks; mileage and/or neighbors&amp;#39; names.&amp;quot;&lt;/p&gt;

&lt;p&gt;Sharon Freas has dealt with systems supporting &amp;quot;&lt;a href=&quot;https://en.wikipedia.org/wiki/Snowbird_%28people%29&quot;&gt;Snowbird&lt;/a&gt;&amp;quot; clients, who alternate between addresses with the changing seasons.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;But written addresses don&amp;#39;t change&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Addresses can move between counties and administrative districts. For example, I used to live in &lt;a href=&quot;https://en.wikipedia.org/wiki/Gwent_%28county%29&quot;&gt;the county Gwent&lt;/a&gt;, but that no longer exists. Addresses may also be assigned new postcodes.&lt;/p&gt;

&lt;p&gt;Susanne Schmidt points out cities, streets and entire countries were renamed in eastern europe - for example, when Lenin fell out of favour as a street name. Addresses can be in disputed territories, or even war zones.&lt;/p&gt;

&lt;p&gt;Douglas Perreault reports owning a condo that changed address three times; first it was 14100 N 46th St., Alpha 39, Lutz, FL 33549; then a new post office was built and it became 14100 N 46th St., Alpha 39, Tampa, FL 33612; then the ZIP Code changed giving 14100 N 46th St., Alpha 39, Tampa, FL 33613; then the condo association changed to a less error-prone block naming scheme, giving 14410 Hanging Moss Circle, #101, Tampa, FL 33613.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Postal, traditional and administrative counties all line up, right?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As you can learn from &lt;a href=&quot;https://en.wikipedia.org/wiki/Postal_counties_of_the_United_Kingdom#Differences&quot;&gt;wikipedia&amp;#39;s page on postal counties&lt;/a&gt;, even when the Royal Mail used postal counties, they didn&amp;#39;t always line up with administrative counties. And of course administrative regions come and go with changes to local government structures - for example, &lt;a href=&quot;https://en.wikipedia.org/wiki/Gwent_%28county%29&quot;&gt;the county I was born in in no longer exists&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- Nongeographical and other special addresses --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Military addresses are just like regular addresses&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Peter Bailey points out several countries have special &lt;a href=&quot;https://en.wikipedia.org/wiki/Military_mail&quot;&gt;military mail&lt;/a&gt; to deal with the complexities of delivering to soldiers deployed to other countries, ships at sea and similar; and their addresses don&amp;#39;t always follow conventional address formats. For example, the address BFPO, BF1 4FB is the address of the navy vessel &lt;a href=&quot;https://en.wikipedia.org/wiki/HMS_Example&quot;&gt;HMS Example&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ed Schiebel reports the postcodes allocated to Israeli army units roam around with the units.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;An address corresponds to the recipient&amp;#39;s location.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Addresses such as &lt;a href=&quot;https://en.wikipedia.org/wiki/Post-office_box&quot;&gt;PO boxes&lt;/a&gt; are often only as precise as the recipient&amp;#39;s city or sorting office. Jessica Enders tells me the Australian post service Reply Paid addresses (no stamp needed); PO Boxes (Post Office Boxes); GPO Boxes (General Post Office Boxes, in the middle of capital cities only); locked bags; private bags; parcel lockers; parcel collect; &amp;quot;Care of Post Office&amp;quot;; CMA (Community Mail Agent); CPA (Community Postal Agent); CMB (Community Mail Bag) and Mail Service (MS)!&lt;/p&gt;

&lt;p&gt;Tibor Schütz points out many post offices have novelty handling of mail to Santa Claus, even going as far as to allocate special postcodes. For example, in Germany: Santa Claus Nordpolen, Julemandes Postkontor, DK-3900 Nuuk; in Canada: Santa Claus, North Pole, H0H 0H0; in the UK: Father Christmas, Santa’s Grotto, Reindeerland, XM4 5HQ&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;An address can be expressed with a single country&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Matthieu Valleton got in touch to point out his address on Kerguelen Island (&lt;a href=&quot;http://maps.google.co.uk/maps?q=Kerguelen+Island&quot;&gt;Google Map&lt;/a&gt;), a French territory in the Indian Ocean, his address was District de Kerguelen (island), Terres Australes et Antarctiques Françaises (territory), via la Réunion (indicates where the mail should be routed through), France (country)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Overseas territories aren&amp;#39;t (or are) always included in the postal code system&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Monty points out that uncommon political hierarchies can lead to uncommon postal addresses. For example, the entire of the Falkland Islands shares postal code FIQQ 1ZZ. On the other hand, the British Virgin Islands have their own postal code system.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;All addresses with a box number are PO Boxes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;David Kuder pointed me to a 1990 article: Risks Digest correspondent &lt;a href=&quot;http://catless.ncl.ac.uk/Risks/9.94.html#subj12.1&quot;&gt;Tim Kay&lt;/a&gt; had problems getting mail sent to his university campus pigeon hole: Timothy L. Kay, Box 256-80, Pasadena, CA 91125. Reportedly automatic systems changed his zip code to 91102. &lt;a href=&quot;http://catless.ncl.ac.uk/Risks/9.96.html#subj8.1&quot;&gt;David Kuder&lt;/a&gt; identified this was because all Pasadena PO Boxes were in box 91102.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- Character sets --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Addresses will be written in ASCII or at least Latin characters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Alastair Houghton reminds us the Greek tax office&amp;#39;s address is Χανδρή 1 &amp;amp; Θεσσαλονίκης, Τ.Κ. 18346, Αθήνα&lt;/p&gt;

&lt;p&gt;Wikipedia has &lt;a href=&quot;https://en.wikipedia.org/wiki/File:Koverto-kun-krakozjabroj.png&quot;&gt;a photo of a parcel&lt;/a&gt; where a Russian/Cyrillic address was displayed on a computer with the wrong character encoding, and transcribed from that. Reportedly a russian postal worker was able to reverse the mapping and deliver the parcel.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/shyhoof/status/332621356338405376&quot;&gt;@shyhoof wrote an poem&lt;/a&gt; about an address label with ó converted, via latin1 and two rounds of HTML entities, into &amp;AMP;AMP;ATILDE;&amp;AMP;AMP;SUP3;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Addresses will be written in the character set of the destination country&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Alastair Houghton points out addresses may be written in the character set of the source country.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;But people at least use the same character set for the entire address?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;International mail may specify the country (and possibly other details) in both the source and destination countries&amp;#39; character sets, so it can be read by postal workers on both ends.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- Ordering of address elements (international) --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Addresses will be written from most to least specific&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Alastair Houghton provided this example of a Japanese address: 〒100-8994 (zip code), 東京都 (Tokyo-to, i.e. Tokyo prefecture or state) 中央区 (Chuo-ku, i.e. Chuo Ward) 八重洲一丁目 (Yaesu 1-chome, i.e. Yaesu district 1st subdistrict) 5番3号 (block 5 lot 3), 東京中央郵便局 (Tokyo Central Post Office). Thanks to Norman Diamond for telling me which parts of the address are which!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;OK, but they&amp;#39;ll either be in either ascending or descending specificity&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Erik Engheim and Jan Jongboom report in Norway and the Netherlands the building number (within street) comes after the street name, but before the town name.&lt;/p&gt;

&lt;p&gt;Douglas Perreault reports units within American condo associations may be written below the street name. For example: 14100 (position of condo association on street) N 46th St. (street name), Alpha (block within condo association) 39 (unit within block), Lutz (city), FL (state) 33549 (zip). Likewise, when mailing an individual at a company some people put the person&amp;#39;s name after the company name, but before the street name.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;OK, but at least the same address will always be written in the same order&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;György Farkas tells me Hungarian addresses can be written in different orders depending on how many lines are available. If you write the address on one line, it&amp;#39;s expressed from less specific to more specific:&lt;/p&gt;

&lt;p&gt;{zip} {town}, {street} {buildingNr}.&lt;/p&gt;

&lt;p&gt;If there are more lines available, the address starts with the street, and if the country is specified, it comes after the town name:&lt;/p&gt;

&lt;p&gt;{street} {buildingNr}.&lt;br /&gt;
 {zip} {town}, {country}&lt;/p&gt;

&lt;p&gt;And if there are no set number of lines, like on an envelope, it&amp;#39;s a bit different again:&lt;/p&gt;

&lt;p&gt;{street} {buildingNr}.&lt;br /&gt;
{town}&lt;br /&gt;
{zip}&lt;br /&gt;
{country}&lt;/p&gt;

&lt;p&gt;Gene Wirchenko tells me in some parts of Canada, suite 123 in building 456 on TheStreet would be written: 123 456 TheStreet whereas in other parts the common formatting is 456 TheStreet #123&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Building numbers appear before street names&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In some countries this is reversed - such as in the Netherlands. For example, Plein 1944 85 D (where Plein 1944 identifies the street, 85 the building and D the flat/apartment).&lt;/p&gt;

&lt;p&gt;Sami Lehtinen provides this example from Finland: Kornetintie 6 A II krs (Kornetintie is the street name, 6 the building number, A the staircase, II krs indicates the second floor.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Flat names/numbers names appear before building numbers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Toni Cornelissen points out addresses in the The Netherlands, such as: Vroomstraat 1a Rood, 2021HL Haarlem where Vroomstaat is the street, 1a is the building number, and Rood (literally translated as Red) indicates the upper part of the building.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- Matching addresses to roads --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A building will be within a few hundred meters of a public road&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Buildings like farms and country houses can be at the end of a private road or driveway several hundred meters long.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;An address with a street name is always closer to that street than any other&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lots of examples of this. For example: The National Museum of Computing, Bletchley Park, Sherwood Drive, Bletchley, Milton Keynes, MK3 6EB. &lt;a href=&quot;https://maps.google.co.uk/maps?q=MK3+6EB&quot;&gt;70m from Roche Gardens, 346m from Sherwood Drive&lt;/a&gt;, but only accessible by entering Bletchley Park from Sherwood Drive.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- Misc --&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Real place names won&amp;#39;t contain rude words&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It&amp;#39;s not just Middlesex and Scunthorpe you have to check for; &lt;a href=&quot;http://maps.geotastic.org/rude/index.php&quot;&gt;Gary Gale has compiled a map of rude-sounding place names.&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A customer will only want reminders mailed to single address&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;John Dye reports that many doctors&amp;#39; offices, dentists and so on are unable to mail both of a child&amp;#39;s divorced parents.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Each person has exactly one address&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tibor Schütz points out people often have a different home and work address.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are other interesting examples in the discussions at &lt;a href=&quot;https://news.ycombinator.com/item?id=5791489&quot;&gt;Hacker News&lt;/a&gt; and &lt;a href=&quot;http://www.reddit.com/r/programming/comments/1fc147/falsehoods_programmers_believe_about_addresses/&quot;&gt;Reddit Programming&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Graham Rhind pointed out the website &lt;a href=&quot;http://www.grcdi.nl/pidm/&quot;&gt;Practical International Data Management&lt;/a&gt; which contains other edge cases (and has added some of the examples from above).&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Miscellaneous</title>
   <link href="https://www.mjt.me.uk/posts/miscellaneous/"/>
   <updated>2012-12-29T00:00:00+00:00</updated>
   <id>https://www.mjt.me.uk/posts/miscellaneous</id>
   <content type="html">&lt;p&gt;Not so much a blog post as things I want to remember the URLs for!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.mjt.me.uk/openjdk_sni_webrev/index.xhtml&quot;&gt;TLS (SSH) Server Name Indication patch for OpenJDK&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.mjt.me.uk/webrev_ksh_webrev/index.xhtml&quot;&gt;Webrev standards-compliant HTML patch&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s a robot:&lt;/p&gt;

&lt;iframe width=&quot;480&quot; height=&quot;390&quot; src=&quot;http://www.youtube.com/embed/dCSt6hcEE0c&quot; frameborder=&quot;0&quot; &gt;There should be a video here.&lt;/iframe&gt;
</content>
 </entry>
 
 
</feed>