CINXE.COM
Ken Shirriff's blog: alto
<!DOCTYPE html> <html class='v2' dir='ltr' xmlns='http://www.w3.org/1999/xhtml' xmlns:b='http://www.google.com/2005/gml/b' xmlns:data='http://www.google.com/2005/gml/data' xmlns:expr='http://www.google.com/2005/gml/expr'> <head> <link href='https://www.blogger.com/static/v1/widgets/3566091532-css_bundle_v2.css' rel='stylesheet' type='text/css'/> <meta content='width=1100' name='viewport'/> <meta content='text/html; charset=UTF-8' http-equiv='Content-Type'/> <meta content='blogger' name='generator'/> <link href='http://www.righto.com/favicon.ico' rel='icon' type='image/x-icon'/> <link href='http://www.righto.com/search/label/alto' rel='canonical'/> <link rel="alternate" type="application/atom+xml" title="Ken Shirriff's blog - Atom" href="http://www.righto.com/feeds/posts/default" /> <link rel="alternate" type="application/rss+xml" title="Ken Shirriff's blog - RSS" href="http://www.righto.com/feeds/posts/default?alt=rss" /> <link rel="service.post" type="application/atom+xml" title="Ken Shirriff's blog - Atom" href="https://www.blogger.com/feeds/6264947694886887540/posts/default" /> <link rel="me" href="https://www.blogger.com/profile/08097301407311055124" /> <!--Can't find substitution for tag [blog.ieCssRetrofitLinks]--> <meta content='http://www.righto.com/search/label/alto' property='og:url'/> <meta content='Ken Shirriff's blog' property='og:title'/> <meta content='Computer history, restoring vintage computers, IC reverse engineering, and whatever' property='og:description'/> <title>Ken Shirriff's blog: alto</title> <style type='text/css'>@font-face{font-family:'Play';font-style:normal;font-weight:400;font-display:swap;src:url(//fonts.gstatic.com/s/play/v19/6aez4K2oVqwIvtU2Gw.eot);}</style> <style id='page-skin-1' type='text/css'><!-- /* ----------------------------------------------- Blogger Template Style Name: Simple Designer: Blogger URL: www.blogger.com ----------------------------------------------- */ /* Variable definitions ==================== <Variable name="keycolor" description="Main Color" type="color" default="#66bbdd"/> <Group description="Page Text" selector="body"> <Variable name="body.font" description="Font" type="font" default="normal normal 12px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="body.text.color" description="Text Color" type="color" default="#222222"/> </Group> <Group description="Backgrounds" selector=".body-fauxcolumns-outer"> <Variable name="body.background.color" description="Outer Background" type="color" default="#66bbdd"/> <Variable name="content.background.color" description="Main Background" type="color" default="#ffffff"/> <Variable name="header.background.color" description="Header Background" type="color" default="transparent"/> </Group> <Group description="Links" selector=".main-outer"> <Variable name="link.color" description="Link Color" type="color" default="#2288bb"/> <Variable name="link.visited.color" description="Visited Color" type="color" default="#888888"/> <Variable name="link.hover.color" description="Hover Color" type="color" default="#33aaff"/> </Group> <Group description="Blog Title" selector=".header h1"> <Variable name="header.font" description="Font" type="font" default="normal normal 60px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="header.text.color" description="Title Color" type="color" default="#3399bb" /> </Group> <Group description="Blog Description" selector=".header .description"> <Variable name="description.text.color" description="Description Color" type="color" default="#777777" /> </Group> <Group description="Tabs Text" selector=".tabs-inner .widget li a"> <Variable name="tabs.font" description="Font" type="font" default="normal normal 14px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="tabs.text.color" description="Text Color" type="color" default="#999999"/> <Variable name="tabs.selected.text.color" description="Selected Color" type="color" default="#000000"/> </Group> <Group description="Tabs Background" selector=".tabs-outer .PageList"> <Variable name="tabs.background.color" description="Background Color" type="color" default="#f5f5f5"/> <Variable name="tabs.selected.background.color" description="Selected Color" type="color" default="#eeeeee"/> </Group> <Group description="Post Title" selector="h3.post-title, .comments h4"> <Variable name="post.title.font" description="Font" type="font" default="normal normal 22px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> </Group> <Group description="Date Header" selector=".date-header"> <Variable name="date.header.color" description="Text Color" type="color" default="#222222"/> <Variable name="date.header.background.color" description="Background Color" type="color" default="transparent"/> <Variable name="date.header.font" description="Text Font" type="font" default="normal bold 11px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="date.header.padding" description="Date Header Padding" type="string" default="inherit"/> <Variable name="date.header.letterspacing" description="Date Header Letter Spacing" type="string" default="inherit"/> <Variable name="date.header.margin" description="Date Header Margin" type="string" default="inherit"/> </Group> <Group description="Post Footer" selector=".post-footer"> <Variable name="post.footer.text.color" description="Text Color" type="color" default="#666666"/> <Variable name="post.footer.background.color" description="Background Color" type="color" default="#f9f9f9"/> <Variable name="post.footer.border.color" description="Shadow Color" type="color" default="#eeeeee"/> </Group> <Group description="Gadgets" selector="h2"> <Variable name="widget.title.font" description="Title Font" type="font" default="normal bold 11px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="widget.title.text.color" description="Title Color" type="color" default="#000000"/> <Variable name="widget.alternate.text.color" description="Alternate Color" type="color" default="#999999"/> </Group> <Group description="Images" selector=".main-inner"> <Variable name="image.background.color" description="Background Color" type="color" default="#ffffff"/> <Variable name="image.border.color" description="Border Color" type="color" default="#eeeeee"/> <Variable name="image.text.color" description="Caption Text Color" type="color" default="#222222"/> </Group> <Group description="Accents" selector=".content-inner"> <Variable name="body.rule.color" description="Separator Line Color" type="color" default="#eeeeee"/> <Variable name="tabs.border.color" description="Tabs Border Color" type="color" default="#eeeeee"/> </Group> <Variable name="body.background" description="Body Background" type="background" color="#f6fbf6" default="$(color) none repeat scroll top left"/> <Variable name="body.background.override" description="Body Background Override" type="string" default=""/> <Variable name="body.background.gradient.cap" description="Body Gradient Cap" type="url" default="url(https://resources.blogblog.com/blogblog/data/1kt/simple/gradients_light.png)"/> <Variable name="body.background.gradient.tile" description="Body Gradient Tile" type="url" default="url(https://resources.blogblog.com/blogblog/data/1kt/simple/body_gradient_tile_light.png)"/> <Variable name="content.background.color.selector" description="Content Background Color Selector" type="string" default=".content-inner"/> <Variable name="content.padding" description="Content Padding" type="length" default="10px" min="0" max="100px"/> <Variable name="content.padding.horizontal" description="Content Horizontal Padding" type="length" default="10px" min="0" max="100px"/> <Variable name="content.shadow.spread" description="Content Shadow Spread" type="length" default="40px" min="0" max="100px"/> <Variable name="content.shadow.spread.webkit" description="Content Shadow Spread (WebKit)" type="length" default="5px" min="0" max="100px"/> <Variable name="content.shadow.spread.ie" description="Content Shadow Spread (IE)" type="length" default="10px" min="0" max="100px"/> <Variable name="main.border.width" description="Main Border Width" type="length" default="0" min="0" max="10px"/> <Variable name="header.background.gradient" description="Header Gradient" type="url" default="none"/> <Variable name="header.shadow.offset.left" description="Header Shadow Offset Left" type="length" default="-1px" min="-50px" max="50px"/> <Variable name="header.shadow.offset.top" description="Header Shadow Offset Top" type="length" default="-1px" min="-50px" max="50px"/> <Variable name="header.shadow.spread" description="Header Shadow Spread" type="length" default="1px" min="0" max="100px"/> <Variable name="header.padding" description="Header Padding" type="length" default="30px" min="0" max="100px"/> <Variable name="header.border.size" description="Header Border Size" type="length" default="1px" min="0" max="10px"/> <Variable name="header.bottom.border.size" description="Header Bottom Border Size" type="length" default="0" min="0" max="10px"/> <Variable name="header.border.horizontalsize" description="Header Horizontal Border Size" type="length" default="0" min="0" max="10px"/> <Variable name="description.text.size" description="Description Text Size" type="string" default="140%"/> <Variable name="tabs.margin.top" description="Tabs Margin Top" type="length" default="0" min="0" max="100px"/> <Variable name="tabs.margin.side" description="Tabs Side Margin" type="length" default="30px" min="0" max="100px"/> <Variable name="tabs.background.gradient" description="Tabs Background Gradient" type="url" default="url(https://resources.blogblog.com/blogblog/data/1kt/simple/gradients_light.png)"/> <Variable name="tabs.border.width" description="Tabs Border Width" type="length" default="1px" min="0" max="10px"/> <Variable name="tabs.bevel.border.width" description="Tabs Bevel Border Width" type="length" default="1px" min="0" max="10px"/> <Variable name="post.margin.bottom" description="Post Bottom Margin" type="length" default="25px" min="0" max="100px"/> <Variable name="image.border.small.size" description="Image Border Small Size" type="length" default="2px" min="0" max="10px"/> <Variable name="image.border.large.size" description="Image Border Large Size" type="length" default="5px" min="0" max="10px"/> <Variable name="page.width.selector" description="Page Width Selector" type="string" default=".region-inner"/> <Variable name="page.width" description="Page Width" type="string" default="auto"/> <Variable name="main.section.margin" description="Main Section Margin" type="length" default="15px" min="0" max="100px"/> <Variable name="main.padding" description="Main Padding" type="length" default="15px" min="0" max="100px"/> <Variable name="main.padding.top" description="Main Padding Top" type="length" default="30px" min="0" max="100px"/> <Variable name="main.padding.bottom" description="Main Padding Bottom" type="length" default="30px" min="0" max="100px"/> <Variable name="paging.background" color="#ffffff" description="Background of blog paging area" type="background" default="transparent none no-repeat scroll top center"/> <Variable name="footer.bevel" description="Bevel border length of footer" type="length" default="0" min="0" max="10px"/> <Variable name="mobile.background.overlay" description="Mobile Background Overlay" type="string" default="transparent none repeat scroll top left"/> <Variable name="mobile.background.size" description="Mobile Background Size" type="string" default="auto"/> <Variable name="mobile.button.color" description="Mobile Button Color" type="color" default="#ffffff" /> <Variable name="startSide" description="Side where text starts in blog language" type="automatic" default="left"/> <Variable name="endSide" description="Side where text ends in blog language" type="automatic" default="right"/> */ /* Content ----------------------------------------------- */ body { font: normal normal 14px Arial, Tahoma, Helvetica, FreeSans, sans-serif; color: #222222; background: #f6fbf6 none repeat scroll top left; padding: 0 40px 40px 40px; } html body .region-inner { min-width: 0; max-width: 100%; width: auto; } h2 { font-size: 22px; } a:link { text-decoration:none; color: #121fb3; } a:visited { text-decoration:none; color: #121fb3; } a:hover { text-decoration:underline; color: #1a00ff; } .body-fauxcolumn-outer .fauxcolumn-inner { background: transparent url(//www.blogblog.com/1kt/simple/body_gradient_tile_light.png) repeat scroll top left; _background-image: none; } .body-fauxcolumn-outer .cap-top { position: absolute; z-index: 1; height: 400px; width: 100%; } .body-fauxcolumn-outer .cap-top .cap-left { width: 100%; background: transparent url(//www.blogblog.com/1kt/simple/gradients_light.png) repeat-x scroll top left; _background-image: none; } .content-outer { -moz-box-shadow: 0 0 40px rgba(0, 0, 0, .15); -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .15); -goog-ms-box-shadow: 0 0 10px #333333; box-shadow: 0 0 40px rgba(0, 0, 0, .15); margin-bottom: 1px; } .content-inner { padding: 10px 10px; } .content-inner { background-color: #ffffff; } /* Header ----------------------------------------------- */ .header-outer { background: #f6fbf7 url(//www.blogblog.com/1kt/simple/gradients_light.png) repeat-x scroll 0 -400px; _background-image: none; } .Header h1 { font: normal normal 42px Play; color: #666666; text-shadow: 1px 2px 3px rgba(0, 0, 0, .2); } .Header h1 a { color: #666666; } .Header .description { font-size: 140%; color: #666666; } .header-inner .Header .titlewrapper { padding: 22px 30px; } .header-inner .Header .descriptionwrapper { padding: 0 30px; } /* Tabs ----------------------------------------------- */ .tabs-inner .section:first-child { border-top: 0 solid #eeeeee; } .tabs-inner .section:first-child ul { margin-top: -0; border-top: 0 solid #eeeeee; border-left: 0 solid #eeeeee; border-right: 0 solid #eeeeee; } .tabs-inner .widget ul { background: #f5f5f5 url(//www.blogblog.com/1kt/simple/gradients_light.png) repeat-x scroll 0 -800px; _background-image: none; border-bottom: 1px solid #eeeeee; margin-top: 0; margin-left: -30px; margin-right: -30px; } .tabs-inner .widget li a { display: inline-block; padding: .6em 1em; font: normal normal 14px Arial, Tahoma, Helvetica, FreeSans, sans-serif; color: #999999; border-left: 1px solid #ffffff; border-right: 1px solid #eeeeee; } .tabs-inner .widget li:first-child a { border-left: none; } .tabs-inner .widget li.selected a, .tabs-inner .widget li a:hover { color: #000000; background-color: #eeeeee; text-decoration: none; } /* Columns ----------------------------------------------- */ .main-outer { border-top: 0 solid #eeeeee; } .fauxcolumn-left-outer .fauxcolumn-inner { border-right: 1px solid #eeeeee; } .fauxcolumn-right-outer .fauxcolumn-inner { border-left: 1px solid #eeeeee; } /* Headings ----------------------------------------------- */ div.widget > h2, div.widget h2.title { margin: 0 0 1em 0; font: normal bold 11px Arial, Tahoma, Helvetica, FreeSans, sans-serif; color: #000000; } /* Widgets ----------------------------------------------- */ .widget .zippy { color: #999999; text-shadow: 2px 2px 1px rgba(0, 0, 0, .1); } .widget .popular-posts ul { list-style: none; } /* Posts ----------------------------------------------- */ h2.date-header { font: normal bold 11px Arial, Tahoma, Helvetica, FreeSans, sans-serif; } .date-header span { background-color: transparent; color: transparent; padding: inherit; letter-spacing: inherit; margin: inherit; } .main-inner { padding-top: 30px; padding-bottom: 30px; } .main-inner .column-center-inner { padding: 0 15px; } .main-inner .column-center-inner .section { margin: 0 15px; } .post { margin: 0 0 25px 0; } h3.post-title, .comments h4 { font: normal normal 22px Arial, Tahoma, Helvetica, FreeSans, sans-serif; margin: .75em 0 0; } .post-body { font-size: 110%; line-height: 1.4; position: relative; } .post-body img, .post-body .tr-caption-container, .Profile img, .Image img, .BlogList .item-thumbnail img { padding: 2px; background: #ffffff; border: 1px solid #ffffff; -moz-box-shadow: 1px 1px 5px rgba(0, 0, 0, .1); -webkit-box-shadow: 1px 1px 5px rgba(0, 0, 0, .1); box-shadow: 1px 1px 5px rgba(0, 0, 0, .1); } .post-body img, .post-body .tr-caption-container { padding: 5px; } .post-body .tr-caption-container { color: #222222; } .post-body .tr-caption-container img { padding: 0; background: transparent; border: none; -moz-box-shadow: 0 0 0 rgba(0, 0, 0, .1); -webkit-box-shadow: 0 0 0 rgba(0, 0, 0, .1); box-shadow: 0 0 0 rgba(0, 0, 0, .1); } .post-header { margin: 0 0 1.5em; line-height: 1.6; font-size: 90%; } .post-footer { margin: 20px -2px 0; padding: 5px 10px; color: #666666; background-color: #f9f9f9; border-bottom: 1px solid #eeeeee; line-height: 1.6; font-size: 90%; } #comments .comment-author { padding-top: 1.5em; border-top: 1px solid #eeeeee; background-position: 0 1.5em; } #comments .comment-author:first-child { padding-top: 0; border-top: none; } .avatar-image-container { margin: .2em 0 0; } #comments .avatar-image-container img { border: 1px solid #ffffff; } /* Comments ----------------------------------------------- */ .comments .comments-content .icon.blog-author { background-repeat: no-repeat; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9sLFwMeCjjhcOMAAAD+SURBVDjLtZSvTgNBEIe/WRRnm3U8RC1neQdsm1zSBIU9VVF1FkUguQQsD9ITmD7ECZIJSE4OZo9stoVjC/zc7ky+zH9hXwVwDpTAWWLrgS3QAe8AZgaAJI5zYAmc8r0G4AHYHQKVwII8PZrZFsBFkeRCABYiMh9BRUhnSkPTNCtVXYXURi1FpBDgArj8QU1eVXUzfnjv7yP7kwu1mYrkWlU33vs1QNu2qU8pwN0UpKoqokjWwCztrMuBhEhmh8bD5UDqur75asbcX0BGUB9/HAMB+r32hznJgXy2v0sGLBcyAJ1EK3LFcbo1s91JeLwAbwGYu7TP/3ZGfnXYPgAVNngtqatUNgAAAABJRU5ErkJggg==); } .comments .comments-content .loadmore a { border-top: 1px solid #999999; border-bottom: 1px solid #999999; } .comments .comment-thread.inline-thread { background-color: #f9f9f9; } .comments .continue { border-top: 2px solid #999999; } /* Accents ---------------------------------------------- */ .section-columns td.columns-cell { border-left: 1px solid #eeeeee; } .blog-pager { background: transparent none no-repeat scroll top center; } .blog-pager-older-link, .home-link, .blog-pager-newer-link { background-color: #ffffff; padding: 5px; } .footer-outer { border-top: 0 dashed #bbbbbb; } /* Mobile ----------------------------------------------- */ body.mobile { background-size: auto; } .mobile .body-fauxcolumn-outer { background: transparent none repeat scroll top left; } .mobile .body-fauxcolumn-outer .cap-top { background-size: 100% auto; } .mobile .content-outer { -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, .15); box-shadow: 0 0 3px rgba(0, 0, 0, .15); } .mobile .tabs-inner .widget ul { margin-left: 0; margin-right: 0; } .mobile .post { margin: 0; } .mobile .main-inner .column-center-inner .section { margin: 0; } .mobile .date-header span { padding: 0.1em 10px; margin: 0 -10px; } .mobile h3.post-title { margin: 0; } .mobile .blog-pager { background: transparent none no-repeat scroll top center; } .mobile .footer-outer { border-top: none; } .mobile .main-inner, .mobile .footer-inner { background-color: #ffffff; } .mobile-index-contents { color: #222222; } .mobile-link-button { background-color: #121fb3; } .mobile-link-button a:link, .mobile-link-button a:visited { color: #ffffff; } .mobile .tabs-inner .section:first-child { border-top: none; } .mobile .tabs-inner .PageList .widget-content { background-color: #eeeeee; color: #000000; border-top: 1px solid #eeeeee; border-bottom: 1px solid #eeeeee; } .mobile .tabs-inner .PageList .widget-content .pagelist-arrow { border-left: 1px solid #eeeeee; } .content-outer { max-width: 1400px !important; } /* fix header */ #header-inner { width: 100% !important; background-position: right !important; } .titlewrapper { padding: 11px 30px 0 !important; } .descriptionwrapper { margin-bottom: 0 !important; } .description { font-size: 120% !important; } /* suppress things */ .date-header { display: none; } #Attribution1 { display: none; } .post-author, .post-timestamp, .reaction-buttons { display: none; } /* h2: sidebar titles */ /* h3: post title */ .post-title , .entry-title { font-size: 180% !important; margin-top: 0 !important; } .entry-title a:link, .entry-title a:visited, .entry-title a:active{ color: #a03; } #main h2 { color:#333; margin-bottom:.4em; margin-top: 13px; font-size:140%; } #main h3 { color:#333; margin-bottom:.4em; margin-top: 13px; font-size:110%; } #main h4 { color:#333; margin-bottom:.5em; } #sidebar-right-1 a:link, #sidebar-right-1 a:visited, #sidebar-right-1 a:active { color: #666; } #sidebar-right-1 h2 { font-size: 100%; color: #666; } /* disable image box */ element.style { } table.chargers img { height: 18px; } table.chargers img { height: 18px; } .post-body img, .post-body .tr-caption-container { padding: 5px; } .post-body img, .post-body .tr-caption-container, .Profile img, .Image img, .BlogList .item-thumbnail img { padding: 0; background: #ffffff; border: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } /* Special items */ a:link img.hilite, a:visited img.hilite { color: #fff; } a:hover img.hilite, a:hover img.hilite2 { color: #f66; } a:active img.hilite { color: #33c; } .hilite {cursor:zoom-in} pre {color:#000000;border:1px solid #000000;} pre.repl { background-color:#e0e0f0; font-size:120%;} pre.arc { background-color:#e0e0f0; font-size:120%;} pre.code { background-color:#e0f0e0; font-size:120%; white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;text-wrap:unrestricted;} code { font-size: 100%;} blockquote { font-size: 110%; background: transparent url("//static.righto.com/images/blockquote.gif") no-repeat 0 0; margin: 20px 0px; padding: 0px 40px;} div.cite {font-size: .8em;.; font-style: italic; color: #888; margin-bottom: 9px;} a.ref { color: gray;vertical-align: super; text-decoration: none; font-size:60%;margin-left: 2px;} a img.hilite { border: 1px solid; color: #888; z-index: 2; } a img.hilite2, a:active img.hilite2 { border: 1px solid; color: #f6fbf6; } table.chargers { border-width: 1px; border-spacing: 2px; border-style: outset; border-color: gray; border-collapse: collapse; background-color: white; } table.chargers th.maker { padding-right: 5px; text-align: right; } table.chargers th { border-width: 1px; padding: 3px; border-style: inset; border-color: gray; background-color: white; text-align: center; } table.chargers img { height: 18px; } table.chargers td { text-align: center; border-width: 1px; padding: 2px 8px; border-style: inset; border-color: gray; background-color: white; } --></style> <style id='template-skin-1' type='text/css'><!-- body { min-width: 750px; } .content-outer, .content-fauxcolumn-outer, .region-inner { min-width: 750px; max-width: 750px; _width: 750px; } .main-inner .columns { padding-left: 0px; padding-right: 240px; } .main-inner .fauxcolumn-center-outer { left: 0px; right: 240px; /* IE6 does not respect left and right together */ _width: expression(this.parentNode.offsetWidth - parseInt("0px") - parseInt("240px") + 'px'); } .main-inner .fauxcolumn-left-outer { width: 0px; } .main-inner .fauxcolumn-right-outer { width: 240px; } .main-inner .column-left-outer { width: 0px; right: 100%; margin-left: -0px; } .main-inner .column-right-outer { width: 240px; margin-right: -240px; } #layout { min-width: 0; } #layout .content-outer { min-width: 0; width: 800px; } #layout .region-inner { min-width: 0; width: auto; } --></style> <meta content='width=device-width, initial-scale=1.0, maximum-scale=12.0, minimum-scale=.25, user-scalable=yes' name='viewport'/> <meta content='mw8ww70r3jW0GzXY6j1d' name='follow_it-verification-code'/> <link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=6264947694886887540&zx=6254c9dd-1d37-4348-98e6-e10fc74c0578' media='none' onload='if(media!='all')media='all'' rel='stylesheet'/><noscript><link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=6264947694886887540&zx=6254c9dd-1d37-4348-98e6-e10fc74c0578' rel='stylesheet'/></noscript> <meta name='google-adsense-platform-account' content='ca-host-pub-1556223355139109'/> <meta name='google-adsense-platform-domain' content='blogspot.com'/> </head> <body class='loading'> <div class='navbar no-items section' id='navbar'> </div> <div itemscope='itemscope' itemtype='http://schema.org/Blog' style='display: none;'> <meta content='Ken Shirriff's blog' itemprop='name'/> </div> <div class='body-fauxcolumns'> <div class='fauxcolumn-outer body-fauxcolumn-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </div> <div class='content'> <div class='content-fauxcolumns'> <div class='fauxcolumn-outer content-fauxcolumn-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </div> <div class='content-outer'> <div class='content-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left content-fauxborder-left'> <div class='fauxborder-right content-fauxborder-right'></div> <div class='content-inner'> <header> <div class='header-outer'> <div class='header-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left header-fauxborder-left'> <div class='fauxborder-right header-fauxborder-right'></div> <div class='region-inner header-inner'> <div class='header section' id='header'><div class='widget Header' data-version='1' id='Header1'> <div id='header-inner' style='background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-4KXwYe0lQ4HFzhAye9vvRlij2ZYvMbfPCnqEE__1o85Fjo3XgefxJQhWRdwR3EzNWNMWT3yMaj2QZaT9GazqQx3C6oWa3-hBNlRHG7f-Oib-lv1Wq_C2_A0rt8xZgs87iNqzRVKK7H0A/s800/background.jpg"); background-position: left; width: 550px; min-height: 105px; _height: 105px; background-repeat: no-repeat; '> <div class='titlewrapper' style='background: transparent'> <h1 class='title' style='background: transparent; border-width: 0px'> <a href='http://www.righto.com/'> Ken Shirriff's blog </a> </h1> </div> <div class='descriptionwrapper'> <p class='description'><span>Computer history, restoring vintage computers, IC reverse engineering, and whatever</span></p> </div> </div> </div></div> </div> </div> <div class='header-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </header> <div class='tabs-outer'> <div class='tabs-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left tabs-fauxborder-left'> <div class='fauxborder-right tabs-fauxborder-right'></div> <div class='region-inner tabs-inner'> <div class='tabs no-items section' id='crosscol'></div> <div class='tabs no-items section' id='crosscol-overflow'></div> </div> </div> <div class='tabs-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <div class='main-outer'> <div class='main-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left main-fauxborder-left'> <div class='fauxborder-right main-fauxborder-right'></div> <div class='region-inner main-inner'> <div class='columns fauxcolumns'> <div class='fauxcolumn-outer fauxcolumn-center-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <div class='fauxcolumn-outer fauxcolumn-left-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <div class='fauxcolumn-outer fauxcolumn-right-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <!-- corrects IE6 width calculation --> <div class='columns-inner'> <div class='column-center-outer'> <div class='column-center-inner'> <div class='main section' id='main'><div class='widget Blog' data-version='1' id='Blog1'> <div class='blog-posts hfeed'> <div class='status-msg-wrap'> <div class='status-msg-body'> Showing posts with label <b>alto</b>. <a href="http://www.righto.com/">Show all posts</a> </div> <div class='status-msg-border'> <div class='status-msg-bg'> <div class='status-msg-hidden'>Showing posts with label <b>alto</b>. <a href="http://www.righto.com/">Show all posts</a></div> </div> </div> </div> <div style='clear: both;'></div> <div class="date-outer"> <div class="date-posts"> <div class='post-outer'> <div class='post hentry' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='https://static.righto.com/images/engelbart/interface-w500.jpg' itemprop='image_url'/> <meta content='6264947694886887540' itemprop='blogId'/> <meta content='4116959493954575947' itemprop='postId'/> <a name='4116959493954575947'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://www.righto.com/2025/03/mother-of-all-demos-usb-keyset-interface.html'>A USB interface to the "Mother of All Demos" keyset</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-4116959493954575947' itemprop='description articleBody'> <p>In the early 1960s, Douglas Engelbart started investigating how computers could augment human intelligence: <!-- https://youtu.be/yJDv-zdhzMY?si=m8GpQSIqnYfNnFsf&t=130)--> "If, in your office, you as an intellectual worker were supplied with a computer display backed up by a computer that was alive for you all day and was instantly responsive to every action you had, how much value could you derive from that?" Engelbart developed many features of modern computing that we now take for granted: the mouse,<span id="fnref:mouse"><a class="ref" href="#fn:mouse">1</a></span> hypertext, shared documents, windows, and a graphical user interface. At the 1968 Joint Computer Conference, Engelbart demonstrated these innovations in a groundbreaking presentation, now known as "The Mother of All Demos."</p> <!-- [Engelbart using the keyset to edit text. Note that the display doesn't support lower case text; instead, upper case is indicated by a line above the character. Adapted from <a href="https://youtu.be/UhpTiWyVa6k?si=cqfTbRsOxTy8eE01">The Mother of All Demos</a>.](keyset-video2.jpg "w500") --> <p><a href="https://static.righto.com/images/engelbart/interface.jpg"><img alt="The keyset with my prototype USB interface." class="hilite" height="364" src="https://static.righto.com/images/engelbart/interface-w500.jpg" title="The keyset with my prototype USB interface." width="500" /></a><div class="cite">The keyset with my prototype USB interface.</div></p> <p>Engelbart's demo also featured an input device known as the keyset, but unlike his other innovations, the keyset failed to catch on. The 5-finger keyset lets you type without moving your hand, entering characters by pressing multiple keys simultaneously as a chord. Christina Englebart, his daughter, loaned one of Engelbart's keysets to me. I constructed an interface to connect the keyset to USB, so that it can be used with a modern computer. The video below shows me typing with the keyset, using the mouse buttons to select upper case and special characters.<span id="fnref:keys"><a class="ref" href="#fn:keys">2</a></span></p> <iframe width="560" height="315" src="https://www.youtube.com/embed/DpshKBKt_os?si=gzyYjd-2_ltR9oeI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> <p>I wrote this blog post to describe my USB keyset interface. Along the way, however, I got sidetracked by the history of The Mother of All Demos and how it obtained that name. It turns out that Engelbart's demo isn't the first demo to be called "The Mother of All Demos".</p> <h2>Engelbart and The Mother of All Demos</h2> <!-- As SRI put it, Doug Engelbart envisioned harnessing the power of computers as tools for collaboration and the augmentation of our collective intelligence to work on humanity's most important problems. --> <p>Engelbart's work has its roots in Vannevar Bush's 1945 visionary essay, "<a href="https://worrydream.com/refs/Bush%20-%20As%20We%20May%20Think%20(Life%20Magazine%209-10-1945).pdf">As We May Think</a>." Bush envisioned thinking machines, along with the "memex", a compact machine holding a library of collective knowledge with hypertext-style links: "The Encyclopedia Britannica could be reduced to the volume of a matchbox." The memex could search out information based on associative search, building up a hypertext-like trail of connections.</p> <p>In the early 1960s, Engelbart was inspired by Bush's essay and set out to develop means to augment human intellect: "increasing the capability of a man to approach a complex problem situation, to gain comprehension to suit his particular needs, and to derive solutions to problems."<span id="fnref:1962"><a class="ref" href="#fn:1962">3</a></span> Engelbart founded the Augmentation Research Center at the Stanford Research Institute (now SRI), where he and his team created a system called NLS (oN-Line System).</p> <p><a href="https://static.righto.com/images/engelbart/shopping-list.jpg"><img alt="Engelbart editing a hierarchical shopping list." class="hilite" height="351" src="https://static.righto.com/images/engelbart/shopping-list-w500.jpg" title="Engelbart editing a hierarchical shopping list." width="500" /></a><div class="cite">Engelbart editing a hierarchical shopping list.</div></p> <p>In 1968, Engelbart demonstrated NLS to a crowd of two thousand people at the Fall Joint Computer Conference. Engelbart gave the demo from the stage, wearing a crisp shirt and tie and a headset microphone. Engelbart created hierarchical documents, such as the shopping list above, and moved around them with hyperlinks. He demonstrated how text could be created, moved, and edited with the keyset and mouse. Other documents included graphics, crude line drawing by today's standards but cutting-edge for the time. The computer's output was projected onto a giant screen, along with video of Engelbart.</p> <p><a href="https://static.righto.com/images/engelbart/keyset-video.jpg"><img alt="Engelbart using the keyset to edit text. Note that the display doesn't support lowercase text; instead, uppercase is indicated by a line above the character. Adapted from The Mother of All Demos." class="hilite" height="354" src="https://static.righto.com/images/engelbart/keyset-video-w500.jpg" title="Engelbart using the keyset to edit text. Note that the display doesn't support lowercase text; instead, uppercase is indicated by a line above the character. Adapted from The Mother of All Demos." width="500" /></a><div class="cite">Engelbart using the keyset to edit text. Note that the display doesn't support lowercase text; instead, uppercase is indicated by a line above the character. Adapted from <a href="https://youtu.be/UhpTiWyVa6k?si=cqfTbRsOxTy8eE01">The Mother of All Demos</a>.</div></p> <p>Engelbart sat at a specially-designed Herman Miller desk<span id="fnref:herman-miller"><a class="ref" href="#fn:herman-miller">6</a></span> that held the keyset, keyboard, and mouse, shown above. While Engelbart was on stage in San Francisco, the SDS 940<span id="fnref:sds940"><a class="ref" href="#fn:sds940">4</a></span> computer that ran the NLS software was 30 miles to the south in Menlo Park.<span id="fnref:moad-video"><a class="ref" href="#fn:moad-video">5</a></span></p> <p>To the modern eye, the demo resembles a PowerPoint presentation over Zoom, as Engelbart collaborated with Jeff Rulifson and Bill Paxton, miles away in Menlo Park. (Just like a modern Zoom call, the remote connection started with "We're not hearing you. How about now?") Jeff Rulifson browsed the NLS code, jumping between code files with hyperlinks and expanding subroutines by clicking on them. NLS was written in custom <a href="https://bitsavers.org/pdf/sri/arc/NLS_Programmers_Guide_Jan76.pdf">high-level languages</a>, which they developed with a "compiler compiler" called <a href="https://en.wikipedia.org/wiki/TREE-META">TREE-META</a>. The NLS system held interactive documentation as well as tracking bugs and changes. Bill Paxton interactively drew a diagram and then demonstrated how NLS could be used as a database, retrieving information by searching on keywords. (Although Engelbart was stressed by the live demo, Paxton told me that he was "too young and inexperienced to be concerned.")</p> <p><a href="https://static.righto.com/images/engelbart/demo-english.jpg"><img alt="Bill Paxton, in Menlo Park, communicating with the conference in San Francisco." class="hilite" height="326" src="https://static.righto.com/images/engelbart/demo-english-w500.jpg" title="Bill Paxton, in Menlo Park, communicating with the conference in San Francisco." width="500" /></a><div class="cite">Bill Paxton, in Menlo Park, communicating with the conference in San Francisco.</div></p> <p>Bill English, an electrical engineer, not only built the first mouse for Engelbart but was also the hardware mastermind behind the demo. In San Francisco, the screen images were projected on a 20-foot screen by a Volkswagen-sized Eidophor projector, bouncing light off a modulated oil film. Numerous cameras, video switchers and mixers created the video image. Two leased microwave links and half a dozen antennas connected SRI in Menlo Park to the demo in San Francisco. High-speed modems send the mouse, keyset, and keyboard signals from the demo back to SRI. Bill English spent months assembling the hardware and network for the demo and then managed the demo behind the scenes, assisted by a team of about 17 people.</p> <p>Another participant was the famed counterculturist Stewart Brand, known for the <a href="https://en.wikipedia.org/wiki/Whole_Earth_Catalog">Whole Earth Catalog</a> and the WELL, one of the oldest online virtual communities. Brand advised Engelbart on the presentation, as well as running a camera. He'd often point the camera at a monitor to generate swirling psychedelic feedback patterns, reminiscent of the LSD that he and Engelbart had experimented with.</p> <p>The demo received press attention such as a San Francisco Chronicle article titled "Fantastic World of Tomorrow's Computer". It stated, "The most fantastic glimpse into the computer future was taking place in a windowless room on the third floor of the Civic Auditorium" where Engelbart "made a computer in Menlo Park do secretarial work for him that ten efficient secretaries couldn't do in twice the time." His goal: "We hope to help man do better what he does—perhaps by as much as 50 per cent." However, the demo received little attention in the following decades.<span id="fnref:attention"><a class="ref" href="#fn:attention">7</a></span></p> <p>Engelbart continued his work at SRI for almost a decade, but as Engelbart commented with frustration, “There was a slightly less than universal perception of our value at SRI”.<span id="fnref:levy"><a class="ref" href="#fn:levy">8</a></span> In 1977, SRI sold the Augmentation Research Center to Tymshare, a time-sharing computing company. (Timesharing was the cloud computing of the 1970s and 1980s, where companies would use time on a centralized computer.) At Tymshare, Engelbart's system was renamed AUGMENT and marketed as an office automation service, but Engelbart himself was sidelined from development, a situation that he <a href="https://stanford.edu/dept/SUL/sites/engelbart/engfmst3-ntb.html">described</a> as sitting in a corner and becoming invisible.</p> <p>Meanwhile, Bill English and some other SRI researchers<span id="fnref:researchers"><a class="ref" href="#fn:researchers">9</a></span> migrated four miles south to Xerox PARC and worked on the Xerox Alto computer. The Xerox Alto incorporated many ideas from the Augmentation Research Center including the graphical user interface, the mouse, and the keyset. The Alto's keyset was almost identical to the Engelbart keyset, as can be seen in the photo below. The Alto's keyset was most popular for the networked 3D shooter game "<a href="https://www.digibarn.com/collections/games/xerox-maze-war/index.html">Maze War</a>", with the clicking of keysets echoing through the hallways of Xerox PARC.</p> <p><a href="https://static.righto.com/images/engelbart/alto.jpg"><img alt="A Xerox Alto with a keyset on the left." class="hilite" height="359" src="https://static.righto.com/images/engelbart/alto-w500.jpg" title="A Xerox Alto with a keyset on the left." width="500" /></a><div class="cite">A Xerox Alto with a keyset on the left.</div></p> <p>Xerox famously failed to commercialize the ideas from the Xerox Alto, but Steve Jobs recognized the importance of interactivity, the graphical user interface, and the mouse when he visited Xerox PARC in 1979. Steve Jobs provided the Apple Lisa and Macintosh ended up with a graphical user interface and the mouse (streamlined to one button instead of three), but he left the keyset behind.<span id="fnref:parc"><a class="ref" href="#fn:parc">10</a></span></p> <p>When McDonnell Douglas acquired Tymshare in 1984, Engelbart and his software—now called Augment—had a new home.<span id="fnref:augment"><a class="ref" href="#fn:augment">11</a></span> In 1987, McDonnell Douglas released a text editor and outline processor for the IBM PC called <a href="https://archive.org/details/1987-augment-mini-base-users-guide_202503">MiniBASE</a>, one of the few PC applications that supported a keyset. The functionality of MiniBASE was almost identical to Engelbart's 1968 demo, but in 1987, MiniBASE was competing against GUI-based word processors such as MacWrite and Microsoft Word, so MiniBASE had little impact. Engelbart left McDonnell Douglas in 1988, forming a research foundation called the <a href="https://www.nytimes.com/1988/09/05/business/business-people-computer-scientist-forming-a-foundation.html">Bootstrap Institute</a> to continue his research independently.</p> <h2>The name: "The Mother of All Demos"</h2> <p>The name "The Mother of All Demos" has its roots in the Gulf War. In August 1990, Iraq invaded Kuwait, leading to war between Iraq and a coalition of the United States and 41 other countries. During the months of buildup prior to active conflict, Iraq's leader, Saddam Hussein, exhorted the Iraqi people to prepare for "<a href="https://www.nytimes.com/1990/09/22/world/confrontation-in-the-gulf-leaders-bluntly-prime-iraq-for-mother-of-all-battles.html">the mother of all battles</a>",<span id="fnref:mother"><a class="ref" href="#fn:mother">12</a></span> a phrase that caught the attention of the media. The battle didn't proceed as Hussein hoped: during <a href="https://www.nytimes.com/1991/02/28/world/war-gulf-president-bush-halts-offensive-combat-kuwait-freed-iraqis-crushed.html">exactly 100 hours</a> of ground combat, the US-led coalition liberated Kuwait, pushed into Iraq, crushed the Iraqi forces, and declared a ceasefire.<span id="fnref:gulf-war"><a class="ref" href="#fn:gulf-war">13</a></span> Hussein's mother of all battles became the <a href="https://www.nytimes.com/1991/02/27/arts/critic-s-notebook-human-images-help-add-drama-to-war-coverage.html">mother of all surrenders</a>.</p> <p>The phrase "mother of all ..." became the 1990s equivalent of a meme, used as a slightly-ironic superlative. It was applied to everything from <a href="https://www.nytimes.com/1993/06/18/sports/us-open-golf-notebook-fore-the-mother-of-all-traffic-jams.html">The Mother of All Traffic Jams</a> to <a href="https://amzn.to/4bzQ7Tc">The Mother of All Windows Books</a>, from <a href="https://cooking.nytimes.com/recipes/1132-the-mother-of-all-butter-cookies">The Mother of All Butter Cookies</a> to Apple calling mobile devices <a href="https://www.nytimes.com/1992/07/19/business/the-executive-computer-mother-of-all-markets-or-a-pipe-dream-driven-by-greed.html">The Mother of All Markets</a>.<span id="fnref:mobile"><a class="ref" href="#fn:mobile">14</a></span></p> <p>In 1991, this superlative was applied to a computer demo, but it wasn't Engelbart's demo. Andy Grove, Intel's president, gave a keynote speech at Comdex 1991 entitled <a href="https://www.youtube.com/watch?v=CwvOeKqXv18">The Second Decade: Computer-Supported Collaboration</a>, a live demonstration of his vision for PC-based video conferencing and wireless communication in the PC's second decade. This complex hour-long demo required almost six months to prepare, with 15 companies collaborating. Intel called this demo "The Mother of All Demos", a name repeated in the New York Times, San Francisco Chronicle, Fortune, and PC Week.<span id="fnref:intel"><a class="ref" href="#fn:intel">15</a></span> Andy Grove's demo was a hit, with over 20,000 people requesting a video tape, but the demo was soon forgotten.</p> <p><a href="https://static.righto.com/images/engelbart/nytimes-moad.jpg"><img alt="On the eve of Comdex, the New York Times wrote about Intel's "Mother of All Demos". Oct 21, 1991, D1-D2." class="hilite" height="357" src="https://static.righto.com/images/engelbart/nytimes-moad-w350.jpg" title="On the eve of Comdex, the New York Times wrote about Intel's "Mother of All Demos". Oct 21, 1991, D1-D2." width="350" /></a><div class="cite">On the eve of Comdex, the New York Times <a href="https://www.nytimes.com/1991/10/21/business/computer-industry-gathers-amid-chaos.html">wrote</a> about Intel's "Mother of All Demos". Oct 21, 1991, D1-D2.</div></p> <p>In 1994, <em>Wired</em> writer Steven Levy wrote <a href="https://amzn.to/4kCE63A">Insanely Great: The Life and Times of Macintosh, the Computer that Changed Everything</a>.<span id="fnref2:levy"><a class="ref" href="#fn:levy">8</a></span> In the second chapter of this comprehensive book, Levy explained how Vannevar Bush and Doug Engelbart "sparked a chain reaction" that led to the Macintosh. The chapter described Engelbart's 1968 demo in detail including a throwaway line saying, "<a href="https://archive.org/details/insanely_great_levy_hard_cover_1994_pdf__mlib/page/42/mode/1up">It was the mother of all demos.</a>"<span id="fnref:vandam"><a class="ref" href="#fn:vandam">16</a></span> Based on my research, I think this is the source of the name "The Mother of All Demos" for Engelbart's demo.</p> <p>By the end of the century, multiple publications echoed Levy's catchy phrase. In February 1999, the San Jose Mercury News had a <a href="https://web.archive.org/web/19991003082606/http://www.mercurycenter.com/svtech/news/special/engelbart/part4.htm">special article</a> on Engelbart, saying that the demonstration was "still called 'the mother of all demos'", a description echoed by the industry publication <a href="https://archive.org/details/sim_computerworld_1999-05-10_33_19/page/n83/mode/1up">Computerworld</a>.<span id="fnref:still"><a class="ref" href="#fn:still">17</a></span> The book <a href="https://archive.org/details/nerds20100step/page/124/mode/2up">Nerds: A Brief History of the Internet</a> stated that the demo "has entered legend as 'the mother of all demos'". By this point, Engelbart's fame for the "mother of all demos" was cemented and the phrase became near-obligatory when writing about him. The classic Silicon Valley history <a href="https://archive.org/details/fireinvalleymaki0000frei">Fire in the Valley</a> (1984), for example, didn't even mention Engelbart but in the <a href="https://archive.org/details/fireinvalleymaki00frei_0/page/303">second edition</a> (2000), "The Mother of All Demos" had its own chapter.</p> <h2>Interfacing the keyset to USB</h2> <p>Getting back to the keyset interface, the keyset consists of five microswitches, triggered by the five levers. The switches are wired to a standard DB-25 connector. I used a <a href="https://www.pjrc.com/store/teensy36.html">Teensy 3.6</a> microcontroller board for the interface, since this board can act both as a USB device and as a USB host. As a USB device, the Teensy can emulate a standard USB keyboard. As a USB host, the Teensy can receive input from a standard USB mouse.</p> <p>Connecting the keyset to the Teensy is (almost) straightforward, wiring the switches to five data inputs on the Teensy and the common line connected to ground. The Teensy's input lines can be configured with pullup resistors inside the microcontroller. The result is that a data line shows <code>1</code> by default and <code>0</code> when the corresponding key is pressed. One complication is that the keyset apparently has a 1.5 k惟 between the leftmost button and ground, maybe to indicate that the device is plugged in. This resistor caused that line to always appear low to the Teensy. To counteract this and allow the Teensy to read the pin, I connected a 1 k惟 pullup resistor to that one line.</p> <h3>The interface code</h3> <p>Reading the keyset and sending characters over USB is mostly straightforward, but there are a few complications. First, it's unlikely that the user will press multiple keyset buttons at exactly the same time. Moreover, the button contacts may bounce. To deal with this, I wait until the buttons have a stable value for 100 ms (a semi-arbitrary delay) before sending a key over USB.</p> <p>The second complication is that with five keys, the keyset only supports 32 characters. To obtain upper case, numbers, special characters, and control characters, the keyset is designed to be used in conjunction with mouse buttons. Thus, the interface needs to act as a USB host, so I can plug in a USB mouse to the interface. If I want the mouse to be usable as a mouse, not just buttons in conjunction with the keyset, the interface mus forward mouse events over USB. But it's not that easy, since mouse clicks in conjunction with the keyset shouldn't be forwarded. Otherwise, unwanted clicks will happen while using the keyset.</p> <p>To emulate a keyboard, the code uses the <a href="https://docs.arduino.cc/language-reference/en/functions/usb/Keyboard/">Keyboard</a> library. This library provides an API to send characters to the destination computer. Inconveniently, the simplest method, <code>print()</code>, supports only regular characters, not special characters like <code>ENTER</code> or <code>BACKSPACE</code>. For those, I needed to use the lower-level <code>press()</code> and <code>release()</code> methods. To read the mouse buttons, the code uses the <a href="https://github.com/PaulStoffregen/USBHost_t36">USBHost_t36</a> library, the Teensy version of the <a href="https://docs.arduino.cc/libraries/usb-host-shield-library-2.0/">USB Host</a> library. Finally, to pass mouse motion through to the destination computer, I use the <a href="https://docs.arduino.cc/language-reference/en/functions/usb/Mouse/">Mouse</a> library.</p> <p>If you want to make your own keyset, Eric Schlaepfer has a model <a href="https://github.com/schlae/engelbart-keyset">here</a>.</p> <h2>Conclusions</h2> <p>Engelbart claimed <!-- https://web.stanford.edu/class/history34q/readings/Engelbart/Engelbart_AugmentWorkshop.html --> that learning a keyset wasn't difficult—a six-year-old kid could learn it in less than a week—but I'm not willing to invest much time into learning it. In my brief use of the keyset, I found it very difficult to use physically. Pressing four keys at once is difficult, with the worst being all fingers except the ring finger. Combining this with a mouse button or two at the same time gave me the feeling that I was sight-reading a difficult piano piece. Maybe it becomes easier with use, but I noticed that Alto programs tended to treat the keyset as function keys, rather than a mechanism for typing with chords.<span id="fnref:alto"><a class="ref" href="#fn:alto">18</a></span> David Liddle of Xerox PARC <a href="https://archive.computerhistory.org/resources/access/text/2020/06/102792010-05-01-acc.pdf#page=9">said</a>, "We found that [the keyset] was tending to slow people down, once you got away from really hot [stuff] system programmers. It wasn't quite so good if you were giving it to other engineers, let alone clerical people and so on."</p> <p>If anyone else has a keyset that they want to connect via USB (unlikely as it may be), my code is on <a href="https://github.com/shirriff/keyset-to-usb-interface">github</a>.<span id="fnref:hackaday"><a class="ref" href="#fn:hackaday">19</a></span> Thanks to Christina Engelbart for loaning me the keyset. Thanks to Bill Paxton for answering my questions. Follow me on Bluesky (<a href="https://bsky.app/profile/righto.com">@righto.com</a>) or <a href="https://www.righto.com/feeds/posts/default">RSS</a> for updates.</p> <h2>Footnotes and references</h2> <div class="footnote"> <ol> <li id="fn:mouse"> <p>Engelbart's use of the mouse wasn't arbitrary, but based on research. In 1966, shortly after inventing the mouse, Engelbart carried out a <a href="https://archive.org/details/nasa_techdoc_19660020914">NASA-sponsored study</a> that evaluated six input devices: two types of joysticks, a Graphacon positioner, the mouse, a light pen, and a control operated by the knees (leaving the hands free). The mouse, knee control, and light pen performed best, with users finding the mouse satisfying to use. Although inexperienced subjects had some trouble with the mouse, experienced subjects considered it the best device.</p> <p><a href="https://static.righto.com/images/engelbart/devices.jpg"><img alt="A joystick, Graphacon, mouse, knee control, and light pen were examined as input devices. Photos from the study." class="hilite" height="546" src="https://static.righto.com/images/engelbart/devices-w600.jpg" title="A joystick, Graphacon, mouse, knee control, and light pen were examined as input devices. Photos from the study." width="600" /></a><div class="cite">A joystick, Graphacon, mouse, knee control, and light pen were examined as input devices. Photos from <a href="https://archive.org/details/nasa_techdoc_19660020914">the study</a>.</div></p> <p><!-- --> <a class="footnote-backref" href="#fnref:mouse" title="Jump back to footnote 1 in the text">↩</a></p> </li> <li id="fn:keys"> <p>The information sheet below from the Augmentation Research Center shows what keyset chords correspond to each character. I used this encoding for my interface software. Each column corresponds to a different combination of mouse buttons.</p> <p><a href="https://static.righto.com/images/engelbart/keyset-sheet-front.jpg"><img alt="The information sheet for the keyset specifies how to obtain each character." class="hilite" height="626" src="https://static.righto.com/images/engelbart/keyset-sheet-front-w400.jpg" title="The information sheet for the keyset specifies how to obtain each character." width="400" /></a><div class="cite">The information sheet for the keyset specifies how to obtain each character.</div></p> <p>The special characters above are <code><CD></code> (Command Delete, i.e. cancel a partially-entered command), <code><BC></code> (Backspace Character), <code><OK></code> (confirm command), <code><BW></code>(Backspace Word), <code><RC></code> (Replace Character), <code><ESC></code> (which does filename completion).</p> <p>NLS and the Augment software have the concept of a <a href="https://dougengelbart.org/content/view/218/">viewspec</a>, a view specification that controls the view of a file. For instance, viewspecs can expand or collapse an outline to show more or less detail, filter the content, or show authorship of sections. The keyset can select viewspecs, as shown below.</p> <p><a href="https://static.righto.com/images/engelbart/keyset-sheet-back.jpg"><img alt="Back of the keyset information sheet." class="hilite" height="621" src="https://static.righto.com/images/engelbart/keyset-sheet-back-w400.jpg" title="Back of the keyset information sheet." width="400" /></a><div class="cite">Back of the keyset information sheet.</div></p> <p>Viewsets are explained in more detail in <a href="https://youtu.be/UhpTiWyVa6k?si=FsrEOWVd4QCszEGI&t=316">The Mother of All Demos</a>. For my keyset interface, I ignored viewspecs since I don't have software to use these inputs, but it would be easy to modify the code to output the desired viewspec characters.</p> <p><!-- --> <a class="footnote-backref" href="#fnref:keys" title="Jump back to footnote 2 in the text">↩</a></p> </li> <li id="fn:1962"> <p>See <a href="https://www.dougengelbart.org/pubs/augment-3906.html">Augmenting Human Intellect: A Conceptual Framework</a>, Engelbart's 1962 report. <a class="footnote-backref" href="#fnref:1962" title="Jump back to footnote 3 in the text">↩</a></p> </li> <li id="fn:sds940"> <p>Engelbart <a href="https://dougengelbart.org/pubs/papers/scanned-original/1968-augment-3954-A-Research-Center-for-Augmenting-Human-Intellect.pdf">used</a> an SDS 940 computer running the Berkeley Timesharing System. The computer had 64K words of core memory, with 4.5 MB of drum storage for swapping and 96 MB of disk storage for files. For displays, the computer drove twelve 5" high-resolution CRTs, but these weren't viewed directly. Instead, each CRT had a video camera pointed at it and the video was redisplayed on a larger display in a work station in each office.</p> <p>The SDS 940 was a large 24-bit scientific computer, built by Scientific Data Systems. Although SDS built the first integrated-circuit-based commercial computer in 1965 (the <a href="https://en.wikipedia.org/wiki/Scientific_Data_Systems#SDS_92">SDS 92</a>), the SDS 940 was a transistorized system. It consisted of multiple refrigerator-sized cabinets, as shown below. Since each memory cabinet held 16K words and the computer at SRI had 64K, SRI's computer had two additional cabinets of memory.</p> <p><a href="https://static.righto.com/images/engelbart/sds940.jpg"><img alt="Front view of an SDS 940 computer. From the Theory of Operation manual." class="hilite" height="370" src="https://static.righto.com/images/engelbart/sds940-w800.jpg" title="Front view of an SDS 940 computer. From the Theory of Operation manual." width="800" /></a><div class="cite">Front view of an SDS 940 computer. From the <a href="http://www.bitsavers.org/pdf/sds/9xx/940/980126A_940_TheoryOfOperation_Mar67.pdf">Theory of Operation</a> manual.</div></p> <p>In the late 1960s, Xerox wanted to get into the computer industry, so Xerox <a href="https://www.nytimes.com/1969/05/16/archives/xerox-joins-computer-industry-xerox-entering-computer-field.html">bought</a> Scientific Data Systems in 1969 for $900 million (about $8 billion in current dollars). The acquisition was a disaster. After steadily losing money, Xerox decided to <a href="https://www.nytimes.com/1975/07/22/archives/computer-making-will-end-at-xerox-844million-writeoff-is-taken-in.html">exit</a> the mainframe computer business in 1975. Xerox's CEO summed up the purchase: "With hindsight, we would not have done the same thing." <a class="footnote-backref" href="#fnref:sds940" title="Jump back to footnote 4 in the text">↩</a></p> </li> <li id="fn:moad-video"> <p>The Mother of All Demos is on <a href="https://www.youtube.com/watch?v=UhpTiWyVa6k">YouTube</a>, as well as a five-minute <a href="https://www.youtube.com/watch?v=B6rKUf9DWRI">summary</a> for the impatient. <a class="footnote-backref" href="#fnref:moad-video" title="Jump back to footnote 5 in the text">↩</a></p> </li> <li id="fn:herman-miller"> <p>The desk for the keyset and mouse was designed by Herman Miller, the office furniture company. Herman Miller worked with SRI to design the desks, chairs, and office walls as part of their plans for the office of the future. Herman Miller invented the cubicle office in 1964, creating a modern replacement for the commonly used open office arrangement. <a class="footnote-backref" href="#fnref:herman-miller" title="Jump back to footnote 6 in the text">↩</a></p> </li> <li id="fn:attention"> <p>Engelbart's demo is famous now, but for many years it was ignored. For instance, Electronic Design had a long <a href="https://archive.org/details/bitsavers_ElectronicignV17N0319690201_71033514/page/25/mode/1up">article</a> on Engelbart's work in 1969 (putting the system on the cover), but there was no mention of the demo.</p> <p><a href="https://static.righto.com/images/engelbart/electronic-design.jpg"><img alt="Engelbart's system was featured on the cover of Electronic Design. Feb 1, 1969. (slightly retouched)" class="hilite" height="398" src="https://static.righto.com/images/engelbart/electronic-design-w500.jpg" title="Engelbart's system was featured on the cover of Electronic Design. Feb 1, 1969. (slightly retouched)" width="500" /></a><div class="cite">Engelbart's system was featured on the <a href="https://archive.org/details/bitsavers_ElectronicignV17N0319690201_71033514/mode/1up">cover</a> of Electronic Design. Feb 1, 1969. (slightly retouched)</div></p> <p>But by the 1980s, the Engelbart demo started getting attention. The 1986 documentary <a href="https://archive.org/details/XD303_86KTEH54_SiliconVllyBoomtown?start=1884.5">Silicon Valley Boomtown</a> had a long section on Engelbart's work and the demo. By 1988, the New York Times was referring to the demo as <a href="https://www.nytimes.com/1988/09/05/business/business-people-computer-scientist-forming-a-foundation.html">legendary</a>. <a class="footnote-backref" href="#fnref:attention" title="Jump back to footnote 7 in the text">↩</a></p> </li> <li id="fn:levy"> <p>Levy had written about Engelbart a decade earlier, in the May 1984 issue of the magazine <a href="https://guidebookgallery.org/articles/ofmiceandmen">Popular Computing</a>. The article focused on the mouse, recently available to the public through the Apple Lisa and the IBM PC (as an option). The big issue at the time was how many buttons a mouse should have: three like Engelbart's mouse, the one button that Apple used, or two buttons as Bill Gates preferred. But Engelbart's larger vision also came through in Levy's interview along with his frustration that most of his research had been ignored, overshadowed by the mouse. Notably, there was no mention of Engelbart's 1968 demo in the article. <a class="footnote-backref" href="#fnref:levy" title="Jump back to footnote 8 in the text">↩</a><a class="footnote-backref" href="#fnref2:levy" title="Jump back to footnote 8 in the text">↩</a></p> </li> <li id="fn:researchers"> <p>The SRI researchers who moved to Xerox include Bill English, Charles Irby, Jeff Rulifson, Bill Duval, and Bill Paxton (<a href="https://web.stanford.edu/class/history34q/readings/Engelbart/Engelbart_AugmentWorkshop.html">details</a>). <a class="footnote-backref" href="#fnref:researchers" title="Jump back to footnote 9 in the text">↩</a></p> </li> <li id="fn:parc"> <p>In 2023, Xerox donated the entire Xerox PARC research center to SRI. The research center remained in Palo Alto but became part of SRI. In a sense, this closed the circle, since many of the people and ideas from SRI had gone to PARC in the 1970s. However, both PARC and SRI had changed radically since the 1970s, with the cutting edge of computer research moving elsewhere. <a class="footnote-backref" href="#fnref:parc" title="Jump back to footnote 10 in the text">↩</a></p> </li> <li id="fn:augment"> <p>For a detailed discussion of the Augment system, see <a href="https://archive.org/details/seyboldreportonw00medi">Tymshare's Augment: Heralding a New Era</a>, Oct 1978. Augment provided a "broad range of information handling capability" that was not available elsewhere. Unlike other word processing systems, Augment was targeted at the professional, not clerical workers, people who were "eager to explore the open-ended possibilities" of the interactive process.</p> <p>The main complaints about Augment were its price and that it was not easy to use. Accessing Engelbart's NLS system over ARPANET cost an eye-watering $48,000 a year (over $300,000 a year in current dollars). Tymshare's Augment service was cheaper (about $80 an hour in current dollars), but still much more expensive than a standard word processing service.</p> <p>Overall, the article found that Augment users were delighted with the system: "It is stimulating to belong to the electronic intelligentsia." Users found it to be "a way of life—an absorbing, enriching experience". <a class="footnote-backref" href="#fnref:augment" title="Jump back to footnote 11 in the text">↩</a></p> </li> <li id="fn:mother"> <p>William Safire provided background in the New York Times, <a href="https://www.nytimes.com/1991/02/24/magazine/on-language-degrading-attrition.html">explaining</a> that "the mother of all battles" originally referred to the battle of Qadisiya in A.D. 636, and Saddam Hussein was referencing that ancient battle. A translator <a href="https://www.nytimes.com/1991/03/07/opinion/l-mother-of-battles-mistranslates-arabic-834791.html">responded</a>, however, that the Arabic expression would be better translated as "the great battle" than "the mother of all battles." <a class="footnote-backref" href="#fnref:mother" title="Jump back to footnote 12 in the text">↩</a></p> </li> <li id="fn:gulf-war"> <p>The end of the Gulf War left Saddam Hussein in control of Iraq and left thousands of US troops in Saudi Arabia. These factors would turn out to be catastrophic in the following years. <a class="footnote-backref" href="#fnref:gulf-war" title="Jump back to footnote 13 in the text">↩</a></p> </li> <li id="fn:mobile"> <p>At the Mobile '92 conference, Apple's CEO, John Sculley, said personal communicators could be "the mother of all markets," while Andy Grove of Intel said that the idea of a wireless personal communicator in every pocket is "a pipe dream driven by greed" (<a href="https://www.nytimes.com/1992/07/19/business/the-executive-computer-mother-of-all-markets-or-a-pipe-dream-driven-by-greed.html">link</a>). In hindsight, Sculley was completely right and Grove was completely wrong. <a class="footnote-backref" href="#fnref:mobile" title="Jump back to footnote 14 in the text">↩</a></p> </li> <li id="fn:intel"> <p>Some references to Intel's "Mother of all demos" are <a href="https://www.nytimes.com/1991/10/21/business/computer-industry-gathers-amid-chaos.html">Computer Industry Gathers Amid Chaos</a>, New York Times, Oct 21, 1991 and "Intel's High-Tech Vision of the Future: Chipmaker proposes using computers to dramatically improve productivity", San Francisco Chronicle, Oct 21, 1991, p24. The title of an article in Microprocessor Report, "Intel Declares Victory in the Mother of All Demos" (Nov. 20, 1991), alluded to the recently-ended war. <a href="https://archive.org/details/fortune135janluce/page/n401/mode/1up">Fortune</a> wrote about Intel's demo in the Feb 17, 1997 issue. A longer description of Intel's demo is in the book <a href="https://books.google.com/books?id=VazSDwAAQBAJ&pg=PA264">Strategy is Destiny</a>. <a class="footnote-backref" href="#fnref:intel" title="Jump back to footnote 15 in the text">↩</a></p> </li> <li id="fn:vandam"> <p>Several sources claim that Andy van Dam was the first to call Engelbart's demo "The Mother of All Demos." Although van Dam attended the 1968 demo, I couldn't find any evidence that he coined the phrase. John Markoff, a technology journalist for The New York Times, wrote a book <a href="https://books.google.com/books?id=cTyfxP-g2IIC&pg=PT228&dq=%22van+dam%22+%22mother+of+all+demos%22&hl=en&newbks=1&newbks_redir=0&sa=X&ved=2ahUKEwiC4ajp7JKMAxWKLkQIHTMiGLoQ6AF6BAgGEAM#v=onepage&q=%22van%20dam%22%20%22mother%20of%20all%20demos%22&f=false">What the Dormouse Said: How the Sixties Counterculture Shaped the Personal Computer Industry</a>. In this book, Markoff wrote about Engelbart's demo, saying "Years later, his talk remained 'the mother of all demos' in the words of Andries van Dam, a Brown University computer scientist." As far as I can tell, van Dam used the phrase but only after it had already been popularized by Levy. <a class="footnote-backref" href="#fnref:vandam" title="Jump back to footnote 16 in the text">↩</a></p> </li> <li id="fn:still"> <p>It's curious to write that the demonstration was <em>still</em> called the "mother of all demos" when the phrase was just a few years old. <a class="footnote-backref" href="#fnref:still" title="Jump back to footnote 17 in the text">↩</a></p> </li> <li id="fn:alto"> <p>The photo below shows a keyset from the Xerox Alto. The five keys are labeled with separate functions—Copy, Undelete, Move, Draw, and Fine— for use with <a href="https://xeroxparcarchive.computerhistory.org/indigo/da/AlePaper.dm!1_/.Ale.paper.html">ALE</a>, a program for IC design. ALE supported <a href="https://xeroxparcarchive.computerhistory.org/ivy/sweet/alto/ale/.ALE.press!1.pdf">keyset chording</a> in combination with the mouse.</p> <p><a class="footnote-backref" href="#fnref:alto" title="Jump back to footnote 18 in the text">↩</a><a href="https://static.righto.com/images/engelbart/alto-keyset.jpg"><img alt="Keyset from a Xerox Alto, courtesy of Digibarn." class="hilite" height="415" src="https://static.righto.com/images/engelbart/alto-keyset-w500.jpg" title="Keyset from a Xerox Alto, courtesy of Digibarn." width="500" /></a><div class="cite">Keyset from a Xerox Alto, courtesy of Digibarn.</div></p> </li> <li id="fn:hackaday"> <p>After I implemented this interface, I came across a project that constructed a 3D-printed chording keyset, also using a Teensy for the USB interface. You can find that project <a href="https://www.pjrc.com/engelbart-chording-keyset/">here</a>. <a class="footnote-backref" href="#fnref:hackaday" title="Jump back to footnote 19 in the text">↩</a></p> </li> </ol> </div> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/6264947694886887540/4116959493954575947' onclick=''> 17 comments: </a> </span> <span class='post-icons'> <span class='item-action'> <a href='https://www.blogger.com/email-post/6264947694886887540/4116959493954575947' title='Email Post'> <img alt='' class='icon-action' height='13' src='http://img1.blogblog.com/img/icon18_email.gif' width='18'/> </a> </span> <span class='item-control blog-admin pid-1138732533'> <a href='https://www.blogger.com/post-edit.g?blogID=6264947694886887540&postID=4116959493954575947&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <span class='post-backlinks post-comment-link'> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=4116959493954575947&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=4116959493954575947&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=4116959493954575947&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=4116959493954575947&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=4116959493954575947&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'><span class='post-labels'> Labels: <a href='http://www.righto.com/search/label/alto' rel='tag'>alto</a>, <a href='http://www.righto.com/search/label/electronics' rel='tag'>electronics</a>, <a href='http://www.righto.com/search/label/reverse-engineering' rel='tag'>reverse-engineering</a> </span> </div> <div class='post-footer-line post-footer-line-3'></div> </div> </div> </div> </div></div> <div class="date-outer"> <div class="date-posts"> <div class='post-outer'> <div class='post hentry' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnowtArnGXarop5d1u2lfv1ljMpAPDH8HWIAGtbjJNPK85aQZVKlWGyMAMK1nqClcVtSbWmS8EUHh37L3zu0afc7sfh2CKeT2oC1EIlqV7VRzkrhzGjHHaM10Kt2RkLMPmVRz7gwQrx8ZZ/w250/alto.jpg' itemprop='image_url'/> <meta content='6264947694886887540' itemprop='blogId'/> <meta content='7766067364173858139' itemprop='postId'/> <a name='7766067364173858139'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://www.righto.com/2018/03/a-1970s-disk-drive-that-wouldnt-seek.html'>A 1970s disk drive that wouldn't seek: getting our Xerox Alto running again</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-7766067364173858139' itemprop='description articleBody'> <p>Our vintage Xerox Alto has been running reliably for months, but a couple weeks ago the disk drive malfunctioned and the heads stopped moving. With a drive that wouldn't seek, our Alto wouldn't work.<span id="fnref:ethernet"><a class="ref" href="#fn:ethernet" rel="footnote">3</a></span> After extensive debugging and studying the drive's complex head movement control system, we discovered that the problem had a trivial fix. This blog post discusses our adventures debugging the Alto's Diablo hard drive and how we got it to work again.</p> <p>The Alto was a revolutionary computer designed at Xerox PARC in 1973 to investigate personal computing. It introduced the GUI, high-resolution bitmapped displays, Ethernet, the optical mouse and laser printers to the world. The Alto I've been restoring came from YCombinator; the restoration team includes Marc Verdiell (<a href="https://www.youtube.com/user/mverdiell/videos">curiousmarc on YouTube</a>), <a href="https://rescue1130.blogspot.com/">Carl Claunch</a> and Luca Severini.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnowtArnGXarop5d1u2lfv1ljMpAPDH8HWIAGtbjJNPK85aQZVKlWGyMAMK1nqClcVtSbWmS8EUHh37L3zu0afc7sfh2CKeT2oC1EIlqV7VRzkrhzGjHHaM10Kt2RkLMPmVRz7gwQrx8ZZ/w9999/alto.jpg"><img alt="The Xerox Alto's disk drive is the unit below the keyboard. The cabinet under the drive holds the computer itself." class="hilite" height="429" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnowtArnGXarop5d1u2lfv1ljMpAPDH8HWIAGtbjJNPK85aQZVKlWGyMAMK1nqClcVtSbWmS8EUHh37L3zu0afc7sfh2CKeT2oC1EIlqV7VRzkrhzGjHHaM10Kt2RkLMPmVRz7gwQrx8ZZ/w250/alto.jpg" title="The Xerox Alto's disk drive is the unit below the keyboard. The cabinet under the drive holds the computer itself." width="250" /></a><div class="cite">The Xerox Alto's disk drive is the unit below the keyboard. The cabinet under the drive holds the computer itself.</div></p> <p>For storage, the Alto used a removable 14" hard disk cartridge that held just 2.5 megabytes. (A user might have multiple cartridges for different purposes, similar to floppies a decade later.) This model 2315 cartridge was invented by IBM in 1964 and became an industry standard, used in minicomputers by HP, DEC, Wang and many other companies. The photo below shows how a disk cartridge is inserted into the Diablo drive. (The drive has been pulled out from the cabinet and its cover removed to show its internal mechanisms.)</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzgJkL6tp1wTQkfwLBc4ZptTHn_GICM6eOLn_HoTntjPq0-R2VaF8xAYQNuWylrF-eRkkzHi6BA-apdaWzH7P5bTfpzxQNOQwYRAV2-rwd5YyMm9UroJnvtXsYVPtl5WsvKTe9KcSRCQt5/w9999/drive.jpg"><img alt="A disk cartridge is inserted into the Alto's drive. The drive has been pulled out and the cover removed, revealing its internals." class="hilite" height="476" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzgJkL6tp1wTQkfwLBc4ZptTHn_GICM6eOLn_HoTntjPq0-R2VaF8xAYQNuWylrF-eRkkzHi6BA-apdaWzH7P5bTfpzxQNOQwYRAV2-rwd5YyMm9UroJnvtXsYVPtl5WsvKTe9KcSRCQt5/w500/drive.jpg" title="A disk cartridge is inserted into the Alto's drive. The drive has been pulled out and the cover removed, revealing its internals." width="500" /></a><div class="cite">A disk cartridge is inserted into the Alto's drive. The drive has been pulled out and the cover removed, revealing its internals.</div></p> <p>Each disk cartridge contains a single platter. The drive has two heads, one for each side of the platter, and the heads seek (move back and forth) in unison. Each side of the disk contains 203 tracks at a density of 100 tracks per inch (.254mm spacing), so the heads need to be positioned with very high accuracy. The heads float 70 microinches (1.8 µm) above the disk surface on a cushion of air, so any contamination on the disk surface can cause a head crash, causing the head to contact the surface and scrape up the oxide layer.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCQTpih50m__df4phzXcGGfS-Dce3RtXrHgTO-Ly5MDEYBThiOUglBuSfcUOhWUltAUW9_1BVqWyM_aYvl5mBc_AVj7FlH5UiztIaXvgHZGhLyh27ZF3KymqjK8ug23u_EbuqZYKgIFt5k/w9999/disk-opened.jpg"><img alt="Opening a disk cartridge reveals the single hard disk platter. The disk isn't scratched; it's just the lighting." class="hilite" height="290" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCQTpih50m__df4phzXcGGfS-Dce3RtXrHgTO-Ly5MDEYBThiOUglBuSfcUOhWUltAUW9_1BVqWyM_aYvl5mBc_AVj7FlH5UiztIaXvgHZGhLyh27ZF3KymqjK8ug23u_EbuqZYKgIFt5k/w400/disk-opened.jpg" title="Opening a disk cartridge reveals the single hard disk platter. The disk isn't scratched; it's just the lighting." width="400" /></a><div class="cite">Opening a disk cartridge reveals the single hard disk platter. The disk isn't scratched; it's just the lighting.</div></p> <p>Our disastrous adventure started when we tried to help out another <a href="http://www.righto.com/2017/11/fixing-ethernet-board-from-vintage.html">Alto owner</a> whose disk drive suffered a head crash.<span id="fnref:headcrash"><a class="ref" href="#fn:headcrash" rel="footnote">1</a></span> (Because of the problems this drive has caused, it will be called the <em>cursed drive</em>, although <em>diabolical</em> fits too.) Replacing the heads in the cursed drive should have taken an hour or so, but became much more complex. I'll describe the full saga of the cursed drive in another post, but to make a long story short we installed new heads that immediately crashed so badly that the head arms were physically bent. After installing another set of heads and fixing various other issues the cursed drive finally seemed to work, so we connected it to our Alto.<span id="fnref:daisychain"><a class="ref" href="#fn:daisychain" rel="footnote">2</a></span> Boot almost worked, except any disk in the cursed drive got hopelessly corrupted. To make things worse, our previously-working drive started seeking erratically and then stopped seeking entirely. We suspected an electrical problem with the cursed drive had damaged the Alto's interface board or the good drive's circuitry. This was rather distressing since now we couldn't use our Alto.<span id="fnref:ethernet"><a class="ref" href="#fn:ethernet" rel="footnote">3</a></span></p> <p>At this point, I should explain a bit about the Diablo drive and the complex mechanism it uses for seeking. The seek circuitry has two purposes. First, when the Alto wants to read from a particular track, the drive must seek, moving the heads to the desired track as fast as possible. Then, the heads must be held perfectly steady over the track. (Keep in mind that a track is only 0.007 inches (.18mm) wide.) Instead of a stepper motor, the drive moves the heads with a DC motor controlled as a servo. To make seeks faster, the motor runs at four different speeds, accelerating quickly and then slowing as it approaches the desired track. Once the head reaches the desired track, the servo mechanism constantly adjusts the head positioner motor to keep the head centered over the track.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9zp15ayp3IpYLufjSyXy4BT8Q-6QqG4Dg1BUKN8N6Z88ka9qEKTwJ_DBmToh4tJ5kaVjKFbPL1Xm-SLi5IJ8DOqw1z2Fv6YHDrN5pHrhbDG1F0FswmkKmnGbQ0AKH-vqgQFSd40gdVYHq/w9999/drive-opened.jpg"><img alt="The Diablo drive's circuitry pulls up for repair. The drive has three circuit boards on the left and three on the right." class="hilite" height="373" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9zp15ayp3IpYLufjSyXy4BT8Q-6QqG4Dg1BUKN8N6Z88ka9qEKTwJ_DBmToh4tJ5kaVjKFbPL1Xm-SLi5IJ8DOqw1z2Fv6YHDrN5pHrhbDG1F0FswmkKmnGbQ0AKH-vqgQFSd40gdVYHq/w500/drive-opened.jpg" title="The Diablo drive's circuitry pulls up for repair. The drive has three circuit boards on the left and three on the right." width="500" /></a><div class="cite">The Diablo drive's circuitry pulls up for repair. The drive has three circuit boards on the left and three on the right.</div></p> <p>The seek logic is implemented by the three circuit boards on the right.<span id="fnref:left"><a class="ref" href="#fn:left" rel="footnote">4</a></span> These boards mostly use simple DTL (Diode Transistor Logic) gates, integrated circuits from the 1960s that predated TTL. The innermost board receives the desired track number from the Alto. The next board computes the difference between the drive's current track and the desired track and determines how fast to move the head. Finally, the rightmost board is the analog board that drives the head positioner motor as well as processing head position signals from the transducer. <span id="fnref:reference"><a class="ref" href="#fn:reference" rel="footnote">5</a></span> In a modern system, the seek logic could be compactly implemented with a microcontroller. But in the 1970s, controlling the heads took three boards full of integrated circuits.</p> <p>The photo below shows the disk heads and the head position transducer, a key component of the seek circuitry.<span id="fnref:servo"><a class="ref" href="#fn:servo" rel="footnote">6</a></span> The heads are in the foreground, two barely-visible white ceramic circles on flat metal arms. The head positioner motor (hidden underneath) moves the heads in and out to the appropriate track. The head position transducer, the green disk in the photo below, provides electronic feedback on the head position. The yellow pointer and the scale on the transducer show the track number visually.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPAp08vvhwkGjA7HabSRpuqj4Y4BqPN8nl5tOkCHVyGKnEjUGtLz2jqLaeWtdrOCiT8YPMASvopZsG9SDRY8CecU0Tr4WuL_xG4BBnJrN2Pw41sOCd7l7vVCyASDxoWHS3mn0PxEv-UXHU/w9999/positioner.jpg"><img alt="The green head positioner transducer provides feedback to the head servo mechanism. The pointer and dial indicate what track the heads are on." class="hilite" height="421" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPAp08vvhwkGjA7HabSRpuqj4Y4BqPN8nl5tOkCHVyGKnEjUGtLz2jqLaeWtdrOCiT8YPMASvopZsG9SDRY8CecU0Tr4WuL_xG4BBnJrN2Pw41sOCd7l7vVCyASDxoWHS3mn0PxEv-UXHU/w400/positioner.jpg" title="The green head positioner transducer provides feedback to the head servo mechanism. The pointer and dial indicate what track the heads are on." width="400" /></a><div class="cite">The green head positioner transducer provides feedback to the head servo mechanism. The pointer and dial indicate what track the heads are on.</div></p> <p>The transducer generates two "<a href="https://en.wikipedia.org/wiki/Rotary_encoder#Incremental_rotary_encoder">quadrature</a>" signals 90° apart, with one pulse per track.<span id="fnref:transducer"><a class="ref" href="#fn:transducer" rel="footnote">7</a></span> The disk drive counts these pulses to determine the current track number. By looking at the phase of the two signals, the drive can determine the direction of head movement.<span id="fnref:mouse"><a class="ref" href="#fn:mouse" rel="footnote">8</a></span> The video below shows the two transducer outputs displayed in X-Y mode on an oscilloscope. As the head is (manually) moved, the dot rotates 360° on the screen for each track. The direction of rotation indicates which way the head is moving. When the head is aligned over the track, the dot is at the top of the screen. Thus, the transducer outputs show the direction of head motion, the number of tracks moved, and alignment over the track.</p> <iframe width="560" height="315" src="https://www.youtube.com/embed/xsefKVUUpnk?rel=0&showinfo=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe> <p>Getting back to our disk drive that had problems seeking, we did some testing and determined that seeking had totally failed. The drive did not seek when requested by the Alto or <a href="https://rescue1130.blogspot.com/2017/07/disk-tool-now-working-for-both-read-and.html">Carl's FPGA-based disk controller</a>. The drive didn't return the head to track 0 when the disk was unloaded. It didn't even hold the head in place over a track. This let us know that the problem was not with the signals from the Alto but something inside the drive.</p> <p>We figured the complex seek control circuitry must have malfunctioned, so our strategy was to swap the three seek board with boards from a spare drive. Then we could replace boards individually until we found which board had the problem. Much to our surprise, the problem still remained even after we swapped the boards.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYfZefNd2D67TkWeyINYfb9ueGZxKcFbuAXsYuvfpeeRYVT9x-v9bv7oh854Gw_v5A0PEKqUvsX9-QuzWrOTXVP56VL9bKCY2OFgum5eZhbrVPZo5_VsOMUOMJRKmhXx3SR8_LEsNr16Cx/w9999/oscilloscope-bad.jpg"><img alt="An oscilloscope trace shows signals in the malfunctioning disk drive. The motor control signal (yellow) causes the motor to be driven with +15V and -15V (pink), but nothing shows up in the current-sensing resistor (green). Xerox Alto oscilloscope-bad.jpg" class="hilite" height="325" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYfZefNd2D67TkWeyINYfb9ueGZxKcFbuAXsYuvfpeeRYVT9x-v9bv7oh854Gw_v5A0PEKqUvsX9-QuzWrOTXVP56VL9bKCY2OFgum5eZhbrVPZo5_VsOMUOMJRKmhXx3SR8_LEsNr16Cx/w500/oscilloscope-bad.jpg" title="An oscilloscope trace shows signals in the malfunctioning disk drive. The motor control signal (yellow) causes the motor to be driven with +15V and -15V (pink), but nothing shows up in the current-sensing resistor (green). Xerox Alto oscilloscope-bad.jpg" width="500" /></a><div class="cite">An oscilloscope trace shows signals in the malfunctioning disk drive. The motor control signal (yellow) causes the motor to be driven with +15V and -15V (pink), but nothing shows up in the current-sensing resistor (green). Xerox Alto oscilloscope-bad.jpg</div></p> <p>Next, we checked out the drive's seek signals with an oscilloscope (above). We found that the seek circuitry was generating a motor control signal (yellow) and the motor driver board was sending +15V or -15V to the head positioner motor (pink). Although these signals weren't really what we expected to see, with full voltage to the motor, the heads should have been moving back and forth rapidly instead of remaining stationary. Also, nothing was showing up across the current-sensing resistor (green).<span id="fnref:oscilloscope"><a class="ref" href="#fn:oscilloscope" rel="footnote">9</a></span></p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhr3X_6CdeKTttDlvrG7YTrLBFEeTVE12AHlA2azPDzM5mPYE8wZt04eNXATCwX3O1SIzIVO2DDFtFjCdzUfQHyRY18NKylEVSDD_qSssw1KASS2209QV9SCM-bZ5zFKouqiOrLLmsvt-Dt/w9999/current-resistor.jpg"><img alt="The head-seek motor is driven through a large current-sensing resistor (left). (A disk cable or terminator is attached to the connector on the right.)" class="hilite" height="288" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhr3X_6CdeKTttDlvrG7YTrLBFEeTVE12AHlA2azPDzM5mPYE8wZt04eNXATCwX3O1SIzIVO2DDFtFjCdzUfQHyRY18NKylEVSDD_qSssw1KASS2209QV9SCM-bZ5zFKouqiOrLLmsvt-Dt/w300/current-resistor.jpg" title="The head-seek motor is driven through a large current-sensing resistor (left). (A disk cable or terminator is attached to the connector on the right.)" width="300" /></a><div class="cite">The head-seek motor is driven through a large current-sensing resistor (left). (A disk cable or terminator is attached to the connector on the right.)</div></p> <p>Although the seek circuitry was complex, the actual motor wiring was fairly simple. The motor received up to +/- 15V from a driver board, and was connected to ground through a large (10W) 0.2Ω current sensing resistor (above). A bypass capacitor across the motor (below) filtered out noise. We suspected a failure of the current-sensing resistor, the bypass capacitor, or the motor itself, so we tested these components. A multimeter verified the resistor hadn't burnt out. A <a href="https://en.wikipedia.org/wiki/LCR_meter">LCR meter</a> showed the capacitor had the right capacitance. We powered the motor directly from a power supply and the heads moved back and forth smoothly. This was a puzzle: all the components tested fine and we had measured voltage from the motor driver board, so why was nothing moving?</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhI57bJuI0-qz9rUFFgtzqG8JiMlwxZktnTFhRTcq4LGtxRh7LwP28F_oWKPBUyq01g-scg7FWCz_Ef44ceV2KSw7bka-Naa0YM2h6mvWyC-Ws5FCu3_i7BY7UphFyX2-6CwbvmJLIaoiuk/w9999/head-motor.jpg"><img alt="The head positioning motor moves the heads back and forth. Drive wires (yellow) are bolted to the motor. A bypass capacitor (black) is connected across the motor." class="hilite" height="394" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhI57bJuI0-qz9rUFFgtzqG8JiMlwxZktnTFhRTcq4LGtxRh7LwP28F_oWKPBUyq01g-scg7FWCz_Ef44ceV2KSw7bka-Naa0YM2h6mvWyC-Ws5FCu3_i7BY7UphFyX2-6CwbvmJLIaoiuk/w400/head-motor.jpg" title="The head positioning motor moves the heads back and forth. Drive wires (yellow) are bolted to the motor. A bypass capacitor (black) is connected across the motor." width="400" /></a><div class="cite">The head positioning motor moves the heads back and forth. Drive wires (yellow) are bolted to the motor. A bypass capacitor (black) is connected across the motor.</div></p> <p>At this point, Carl noticed that one of the wires on the motor was loose. He tightened the nut and the seek problems were immediately solved. After all our investigation, the problem with our drive was simply a loose wire that prevented power from getting to the motor. Vibration must have slowly loosened the nut until the drive quit working. Apparently it was just coincidence that the problem happened when we had the cursed drive connected.</p> <h2>Conclusion</h2> <p>It was a bit anticlimactic to find a simple loose wire after all our investigation of the seek circuitry. But we were happy to have our drive back in operation, so we could use our Alto again. We still have to diagnose the problem with the cursed drive, but hopefully we're getting closer; I plan to write another blog post once we get that problem solved.</p> <p>My full set of Alto posts is <a href="http://www.righto.com/search/label/alto">here</a>. Follow me on <a href="https://twitter.com/kenshirriff">Twitter</a> or <a href="http://www.righto.com/feeds/posts/default">RSS</a> to find out about my latest blog posts.</p> <h2>Notes and references</h2> <div class="footnote"> <ol> <li id="fn:headcrash"> <p>Since the head flies at high speed above the disk surface, any particles on the disk can cause the head to crash into the disk surface, scratching the disk and clogging up the head with oxide. Usually the heads can be removed and cleaned. After reinstalling the heads, they need to be realigned with a special alignment pack so they are properly positioned over the tracks. <a class="footnote-backref" href="#fnref:headcrash" rev="footnote" title="Jump back to footnote 1 in the text">↩</a></p> </li> <li id="fn:daisychain"> <p>The disk drives have two connectors on the back, so multiple drives can be daisy-chained together. This lets you have a two-drive Alto configuration, for instance. A terminator is connected to the last disk in the chain. Thus, the Alto was connected to the working drive in the Alto cabinet, which was then connected to the cursed drive. <a class="footnote-backref" href="#fnref:daisychain" rev="footnote" title="Jump back to footnote 2 in the text">↩</a></p> </li> <li id="fn:ethernet"> <p>Our Alto wasn't totally dead without a disk drive, since we could boot over Ethernet using my <a href="http://www.righto.com/2018/01/xerox-altos-3-mbs-ethernet-building.html">Ethernet gateway</a>. However, without a working disk drive the Alto was very limited. <a class="footnote-backref" href="#fnref:ethernet" rev="footnote" title="Jump back to footnote 3 in the text">↩</a></p> </li> <li id="fn:left"> <p>The three boards on the left of the drive aren't relevant for this repair, but I'll describe them for completeness. The leftmost board (J10) has the analog read/write circuitry that drives the heads. (You can see a wire from the upper left corner of the board going to the heads.) The next board (J9) controls the spindle drive motor, lowers the heads onto the disk after loading, and detects sector marks. The inner board on the left (J8) counts the sectors on the disk. It also generates the 5V supply and has an oscillator to drive the head position transducer. <a class="footnote-backref" href="#fnref:left" rev="footnote" title="Jump back to footnote 4 in the text">↩</a></p> </li> <li id="fn:reference"> <p>The <a href="http://bitsavers.org/pdf/diablo/disk/model_30/81503-02_Series_30_Disk_Drive_Maintenance_Nov75.pdf">Disk drive maintenance manual</a> includes schematics and a detailed description of the drive's operation. <a class="footnote-backref" href="#fnref:reference" rev="footnote" title="Jump back to footnote 5 in the text">↩</a></p> </li> <li id="fn:servo"> <p>Modern disk drives position the heads based on a <a href="http://www.computerhistory.org/storageengine/track-following-servo-quadruples-hdd-density/">servo track</a> written on the disk, a technology developed in 1971 that provided better positioning accuracy. The Diablo drive on the other hand, used older technology where position feedback was part of the drive. <a class="footnote-backref" href="#fnref:servo" rev="footnote" title="Jump back to footnote 6 in the text">↩</a></p> </li> <li id="fn:transducer"> <p>The head position rotary transducer uses a special transformer to generate the position signals. A 50 kHz carrier signal is fed into the transducer. This signal is modulated based on the head position to yield two signals, the quadrature signals 90° out of phase. The transducer has two parts: a rotary member that receives the carrier signal, and a stationary member that provides the two output signals. I haven't disassembled the transducer, but based on <a href="http://www.inductosyn.com/PDF%20Files/Farrand%20Controls%20Brochure.pdf">similar rotary transducers</a>, I believe the transducer is built from zig-zag windings etched into circular printed circuit boards in the transducer. The zig-zags are closely spaced around the transducer disk, with their spacing matching one track's rotation of the transducer disk. The two output windings have the same spacing, but are offset one quarter of a zig-zag, i.e. 90°. As the transducer rotates, the input winding will line up alternately in phase and opposite phase with the output winding, yielding a positive and then negative output, once per track. The other output winding behaves similarly, but 90° out of phase. <a class="footnote-backref" href="#fnref:transducer" rev="footnote" title="Jump back to footnote 7 in the text">↩</a></p> </li> <li id="fn:mouse"> <p>A mechanical mouse uses a <a href="http://www.fpga4fun.com/QuadratureDecoder.html">similar quadrature technique</a> to determine the direction of motion. A mechanical mouse typically uses optical encoders rather than the disk drive's transformer encoders. <a class="footnote-backref" href="#fnref:mouse" rev="footnote" title="Jump back to footnote 8 in the text">↩</a></p> </li> <li id="fn:oscilloscope"> <p>We used an oscilloscope to examine the seek circuitry on a working drive, and found very complex, almost chaotic signals showing the constant adjustments of the servo circuitry to keep the head aligned.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQtEJsD3HllHDHXyjzETBL0p6We8MFZIybCjQ2etEKdryNZ3zRaycDFt4PYpvOH61A2xYBtN-q8EUCmIAs8-AZvIu0NAf_QIcl_o_K7Gi45qxBcO-OyGYJ6nTUiK96cUsftZDTdgTkkui8/w9999/oscilloscope-good.jpg"><img alt="A working disk drive shows the complex signals in the servo mechanism. The input signal (blue) triggers variations in the motor control signal (yellow). The motor voltage (pink) is constantly adjusted so the motor current (green) tracks the control signal." class="hilite" height="347" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQtEJsD3HllHDHXyjzETBL0p6We8MFZIybCjQ2etEKdryNZ3zRaycDFt4PYpvOH61A2xYBtN-q8EUCmIAs8-AZvIu0NAf_QIcl_o_K7Gi45qxBcO-OyGYJ6nTUiK96cUsftZDTdgTkkui8/w500/oscilloscope-good.jpg" title="A working disk drive shows the complex signals in the servo mechanism. The input signal (blue) triggers variations in the motor control signal (yellow). The motor voltage (pink) is constantly adjusted so the motor current (green) tracks the control signal." width="500" /></a><div class="cite">A working disk drive shows the complex signals in the servo mechanism. The input signal (blue) triggers variations in the motor control signal (yellow). The motor voltage (pink) is constantly adjusted so the motor current (green) tracks the control signal.</div></p> <p>The signals from the transducer are processed, combined, and differentiated to generate spikes (blue) as the head moves. This input is filtered to form the motor control signal (yellow). The voltage driving the head motor (pink) is constantly adjusted so the velocity signal (green, from the current-sense resistor) is proportional to the control signal (yellow). <a class="footnote-backref" href="#fnref:oscilloscope" rev="footnote" title="Jump back to footnote 9 in the text">↩</a></p> </li> </ol> </div> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/6264947694886887540/7766067364173858139' onclick=''> 5 comments: </a> </span> <span class='post-icons'> <span class='item-action'> <a href='https://www.blogger.com/email-post/6264947694886887540/7766067364173858139' title='Email Post'> <img alt='' class='icon-action' height='13' src='http://img1.blogblog.com/img/icon18_email.gif' width='18'/> </a> </span> <span class='item-control blog-admin pid-1138732533'> <a href='https://www.blogger.com/post-edit.g?blogID=6264947694886887540&postID=7766067364173858139&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <span class='post-backlinks post-comment-link'> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=7766067364173858139&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=7766067364173858139&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=7766067364173858139&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=7766067364173858139&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=7766067364173858139&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'><span class='post-labels'> Labels: <a href='http://www.righto.com/search/label/alto' rel='tag'>alto</a>, <a href='http://www.righto.com/search/label/electronics' rel='tag'>electronics</a> </span> </div> <div class='post-footer-line post-footer-line-3'></div> </div> </div> </div> </div></div> <div class="date-outer"> <div class="date-posts"> <div class='post-outer'> <div class='post hentry' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOp5b76CpWTRn2CIdgbch7po9zeBn5AjVihaCyQZrIR2LPTKzuZXy9eH5mcTEMMinquPpH3e0Ip1kM08MetgNmZk6bhD_e1T7d9eP4OFPS_wjur5EvG1jvomKewk_yW-tctDZWnIzuRNjr/w400/inside-transceiver.jpg' itemprop='image_url'/> <meta content='6264947694886887540' itemprop='blogId'/> <meta content='1182972412801248728' itemprop='postId'/> <a name='1182972412801248728'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://www.righto.com/2018/01/xerox-altos-3-mbs-ethernet-building.html'>Xerox Alto's 3 Mb/s Ethernet: Building a gateway with a BeagleBone</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-1182972412801248728' itemprop='description articleBody'> <style> code {background-color:#eee;font-size: 80%;} .gist table.lines { font-size: 12px; line-height: 10px; } .gist-meta { font-size: 80% !important; } .gist .blob-num { line-height: 10px !important;} .gist .blob-code { line-height: 10px !important;} </style> <p>The Alto was a revolutionary computer designed at Xerox PARC in 1973. It introduced the GUI, high-resolution bitmapped displays, the optical mouse and laser printers to the world. But one of its most important contributions was Ethernet, the local area network that is still heavily used today. While modern Ethernets handle up to 100 gigabits per second, the Alto's Ethernet was much slower, just 3 megabits per second over coaxial cable. Even so, the Alto used the Ethernet for file servers, email, distributed games, network boot, and even voice over Ethernet.</p> <p>The Alto's 3 Mb/s Ethernet isn't compatible with modern Ethernet, making it difficult to transfer data between an Alto and the outside world. To solve this, I built a gateway using the BeagleBone single-board computer to communicate with the Alto's Ethernet. In this article I discuss how the Alto's Ethernet works and how I implemented the gateway.</p> <h2>The Alto's Ethernet hardware</h2> <p>The Alto's Ethernet used a coaxial cable, rather than modern twisted-pair cable. A transceiver box was the interface between the Alto and the cable, converting the Alto's logic signals to the signals on the cable. In the photo below, you can see a transceiver clamped onto the coaxial cable; a "vampire tap" punctures the cable making contact with the central conductor.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOp5b76CpWTRn2CIdgbch7po9zeBn5AjVihaCyQZrIR2LPTKzuZXy9eH5mcTEMMinquPpH3e0Ip1kM08MetgNmZk6bhD_e1T7d9eP4OFPS_wjur5EvG1jvomKewk_yW-tctDZWnIzuRNjr/w9999/inside-transceiver.jpg"><img alt="Inside a transceiver box. The "vampire tap" on the right connects the transceiver to the Ethernet cable. The connector on the left goes to the Alto." class="hilite" height="299" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOp5b76CpWTRn2CIdgbch7po9zeBn5AjVihaCyQZrIR2LPTKzuZXy9eH5mcTEMMinquPpH3e0Ip1kM08MetgNmZk6bhD_e1T7d9eP4OFPS_wjur5EvG1jvomKewk_yW-tctDZWnIzuRNjr/w400/inside-transceiver.jpg" title="Inside a transceiver box. The "vampire tap" on the right connects the transceiver to the Ethernet cable. The connector on the left goes to the Alto." width="400" /></a><div class="cite">Inside a transceiver box. The "vampire tap" on the right connects the transceiver to the Ethernet cable. The connector on the left goes to the Alto.</div></p> <p>The Alto's Ethernet uses Manchester encoding of the bits. That is, a "1" is sent as "10" and a "0" is sent as "01". The reason to do this instead of just sending the raw bits is the Manchester encoding is self-clocking—there's a transition for every bit. If instead you just sent a raw stream of bits, e.g. "00000000000", the receiver would have a hard time knowing where the bits start and end. The figure below shows how <code>0110</code> is transmitted with Manchester encoding.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhX4sQTPOebOOZRdAKDLExsktro7tIA0Debxr1v3DOwggUBjLxvPMLwIqElwuMbgOvhAdaAPWPqvCRtyK4NGPEiQqgtt7b9hfO-RtQjeGH_jmNmo_BUNS1m_UletfrSWCZYZMbBzwfOD4mN/w9999/waveform1.png"><img alt="An example of Manchester encoding, for the bits 0110." class="hilite" height="92" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhX4sQTPOebOOZRdAKDLExsktro7tIA0Debxr1v3DOwggUBjLxvPMLwIqElwuMbgOvhAdaAPWPqvCRtyK4NGPEiQqgtt7b9hfO-RtQjeGH_jmNmo_BUNS1m_UletfrSWCZYZMbBzwfOD4mN/w250/waveform1.png" title="An example of Manchester encoding, for the bits 0110." width="250" /></a><div class="cite">An example of Manchester encoding, for the bits 0110.</div></p> <h2>The Alto's network protocols</h2> <p>The Alto predates TCP/IP, instead using a protocol called Pup (the PARC Universal Packet).<span id="fnref:pup"><a class="ref" href="#fn:pup" rel="footnote">1</a></span> The protocol has many similarities with TCP/IP, since the Pup designers influenced the TCP design based on their experience. The basic Pup Internet Datagram is analogous to an IP packet. A packet contains a destination address for the packet consisting of a network id (1 byte), a host id on the network (1 byte), and a 4-byte socket. A machine's host id is specified by jumper wires on the backplane (below). Thus, packets can be routed through a large network to the right machine.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOxgT41YfDtmkPvgi7J5DAuVtEm2umvs0GiSewUZYAYUdEsGu4YzYcgTThfT_ik9ThMpAuIcORdvHYf_wsZBtCCQD4V2fVTnCDpmtHIO1BjnmN4K7iKlnzvpJBrf0Nw8Bu5Lsa6cK7Ctf1/w9999/backplane-jumpers.jpg"><img alt="Long blue jumper wires on the Alto's backplane specify the system's Ethernet address." class="hilite" height="288" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOxgT41YfDtmkPvgi7J5DAuVtEm2umvs0GiSewUZYAYUdEsGu4YzYcgTThfT_ik9ThMpAuIcORdvHYf_wsZBtCCQD4V2fVTnCDpmtHIO1BjnmN4K7iKlnzvpJBrf0Nw8Bu5Lsa6cK7Ctf1/w250/backplane-jumpers.jpg" title="Long blue jumper wires on the Alto's backplane specify the system's Ethernet address." width="250" /></a><div class="cite">Long blue jumper wires on the Alto's backplane specify the system's Ethernet address.</div></p> <p>Some simple network operations just exchanged Pup packets, for example requesting the time from a network server. But for more complex operations, Xerox built layers on top of Pup. For a long-lived connection between two machines, Xerox built RTP (Rendezvous/Termination Protocol), a protocol to establish connections between two ports. This is analogous to a TCP socket connection. Once the connection is established, the computers can communicate using Byte Steam Protocol (BSP). This protocol handles error correction and flow control, very similar to TCP.</p> <p>On top of these protocols, Xerox implemented email, FTP (File Transfer Protocol), network boot, networked games such as <a href="https://en.wikipedia.org/wiki/Maze_War">Maze War</a>, network error reporting, network disk backups and the first <a href="https://people.eecs.berkeley.edu/~prabal/resources/osprelim/SH82.pdf">computer worm</a>.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOXyCHkYQwDeilqYN_nhnJH8ZymxqRaU0OmeBc0_WE2babYaxiNLstH_HOPm9vvY9uawBh0LNrNtnFnf4F0q5i36wMlG2V9aNMOYPlmIx3cDCpUUzs7Rc9HtV8L7TvZiZXid3LLiYsN0xw/w9999/network-map.png"><img alt="Map of the Xerox PARC network, showing important servers. May 1978. From Alto User's Primer." class="hilite" height="504" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOXyCHkYQwDeilqYN_nhnJH8ZymxqRaU0OmeBc0_WE2babYaxiNLstH_HOPm9vvY9uawBh0LNrNtnFnf4F0q5i36wMlG2V9aNMOYPlmIx3cDCpUUzs7Rc9HtV8L7TvZiZXid3LLiYsN0xw/w500/network-map.png" title="Map of the Xerox PARC network, showing important servers. May 1978. From Alto User's Primer." width="500" /></a><div class="cite">Map of the Xerox PARC network, showing important servers. May 1978. From <a href="http://xeroxalto.computerhistory.org/_cd8_/altodocs/.altousersprimer.press!2.pdf">Alto User's Primer</a>.</div></p> <h2>Designing an Ethernet gateway</h2> <p>I decided to build a gateway that would allow the Alto to communicate with a modern system. The gateway would communicate with the Alto using its obsolete 3Mb/s Ethernet, but could also communicate with the outside world. This would let us network boot the Alto, transfer files to and from the Alto and backup disks. I expected this project to take a few weeks, but it ended up taking a year.</p> <p>The first decision was what hardware platform to use. My plan was to use a microcontroller to generate the 3Mb/s signals by "bit banging", i.e. directly generating the 1's and 0's on the wire. (A regular processor couldn't handle this in real time, due to interrupts and task switching.) But a microcontroller wouldn't be suitable for running the network stack and communicating with the outside world; I'd need a "real computer" for that. Someone suggested the BeagleBone: a credit-card sized Linux computer with an ARM processor that also incorporated two microcontrollers. This would provide a compact, low-cost implementation, so I started investigating the BeagleBone.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4WXXb41L8tjhoNT5Hci6ATZYsJXDfljUpNHvc5_-9c5kxEFraSC6BqcGlTDcG5eU7fNPp1xpJwznLxhLuBpB3bE-VSK6Kgne2bCBfEOJeDlErzN4ZUZM4xs1Jg8-qLyg35lUCDlZpUNS8/w9999/altoids2.jpg"><img alt="The BeagleBone single-board Linux computer is small enough to fit in an Altoids tin. It has many general/purpose I/O pins, accessible through the connectors along the top and bottom of the board." class="hilite" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4WXXb41L8tjhoNT5Hci6ATZYsJXDfljUpNHvc5_-9c5kxEFraSC6BqcGlTDcG5eU7fNPp1xpJwznLxhLuBpB3bE-VSK6Kgne2bCBfEOJeDlErzN4ZUZM4xs1Jg8-qLyg35lUCDlZpUNS8/w300/altoids2.jpg" title="The BeagleBone single-board Linux computer is small enough to fit in an Altoids tin. It has many general/purpose I/O pins, accessible through the connectors along the top and bottom of the board." width="300" /></a><div class="cite">The BeagleBone single-board Linux computer is small enough to fit in an Altoids tin. It has many general/purpose I/O pins, accessible through the connectors along the top and bottom of the board.</div></p> <p>The BeagleBone's microcontrollers, called PRUs,<span id="fnref:pru"><a class="ref" href="#fn:pru" rel="footnote">2</a></span> are designed to run each instruction in a single 5ns cycle. Since the Ethernet pulses are 170ns wide, I figured I had plenty of time to send and receive signals. (It turned out that getting everything done in 170ns was challenging, but it worked out in the end.) In my gateway, the PRU reads the Ethernet signal coming from the Alto, and generate the Ethernet signal going to the Alto, as well as sending a network collision signal to the Alto.</p> <p>In case you're wondering what PRU code looks like, the C code fragment below shows how a byte is encoded and sent. The PRU code outputs the right sequence of HIGH/LOW or LOW/HIGH pulses (the Manchester encoding), making sure each part is 170ns wide. Each bit of register <code>R30</code> controls an output pin, so the bit for the Ethernet write pin is set and cleared as needed. <code>wait_for_pwm_timer()</code> provides the 170ns timing for each pulse. The full code is <a href="https://github.com/shirriff/alto-ethernet-interface/blob/master/src/main.c">here</a>.</p> <script src="https://gist.github.com/shirriff/05d8a44ab844f959db86b28d8d27fb28.js"></script> <p>To receive data from Ethernet, my PRU code doesn't do any decoding; it just measures the time between input transitions and sends these timings to the BeagleBone's ARM processor. Originally my code decoded the Manchester encoding into bits and assembled the bits into words, but 170ns wasn't enough time to do this reliably. Instead, since this decoding doesn't need to be done in real time, I moved the decoding to the more powerful ARM processor. The ARM processor also does the higher-level Ethernet protocol handling, such as generating and checking packet checksums.</p> <p>Rather than deal with transceivers and coaxial cable, I connected the BeagleBone to the Alto's Ethernet port directly, omitting the transceiver that normally connects to this port. This port provides standard 5V TTL signals to the transceiver, but the BeagleBone inconveniently uses 3.3V signals. I needed a circuit to translate the voltage levels between the BeagleBone and the Alto. This should have been easy, but I ran into various problems along the way.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjv4qwJbuEiBHuf-2VVMiCIv02L3ae_ndQibsslN2Ct4O_ruHWGzyNDLvGU8DRZ-otXjPgzQs6N4bcaN905RPQI3IRXHzh0kX16U6-Cn7R-r1DuJpfmipbtj_v4goc1ULfXXKA3X-NwbWjG/w9999/ethernet-connector.jpg"><img alt="On the back of the Alto, Ethernet is accessed via a DB-25 connector that connects to a transceiver box." class="hilite" height="205" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjv4qwJbuEiBHuf-2VVMiCIv02L3ae_ndQibsslN2Ct4O_ruHWGzyNDLvGU8DRZ-otXjPgzQs6N4bcaN905RPQI3IRXHzh0kX16U6-Cn7R-r1DuJpfmipbtj_v4goc1ULfXXKA3X-NwbWjG/w300/ethernet-connector.jpg" title="On the back of the Alto, Ethernet is accessed via a DB-25 connector that connects to a transceiver box." width="300" /></a><div class="cite">On the back of the Alto, Ethernet is accessed via a DB-25 connector that connects to a transceiver box.</div></p> <p>I built a prototype voltage translation circuit on a breadboard, using a <a href="https://www.adafruit.com/product/1787">74AHCT125</a> level shifter chip (<a href="https://github.com/shirriff/alto-ethernet-interface/blob/master/board/schematic.pdf">schematic</a>). However, I was getting no Ethernet signal at all from the Alto, so I started probing the Alto's board for a malfunction. I discovered that although the Alto's schematic showed pull-up resistors, these resistors didn't exist on the Alto's Ethernet board (see photo below). Without a resistor, the open-collector signal stayed at ground. Adding the resistors to my circuit fixed that problem.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhf0ILnTNce4n-29hG2eMod5IH_adVtrJmmvGEPtZY-sVEtXAljBS3uFxqX8dkDsfWlXkRoKiiTlaHTWJAy4Cl0tnE0dRfjdbQDGCanaxAzb2FNko5cuCMnsmEbf0vOUv_wznXdnzNG-oIn/w9999/missing-resistors.jpg"><img alt="One problem I encountered was termination resistors R8 and R9 appeared on the schematic but were missing from the board (above the word "ETHERNET")." class="hilite" height="257" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhf0ILnTNce4n-29hG2eMod5IH_adVtrJmmvGEPtZY-sVEtXAljBS3uFxqX8dkDsfWlXkRoKiiTlaHTWJAy4Cl0tnE0dRfjdbQDGCanaxAzb2FNko5cuCMnsmEbf0vOUv_wznXdnzNG-oIn/w400/missing-resistors.jpg" title="One problem I encountered was termination resistors R8 and R9 appeared on the schematic but were missing from the board (above the word "ETHERNET")." width="400" /></a><div class="cite">One problem I encountered was termination resistors R8 and R9 appeared on the schematic but were missing from the board (above the word "ETHERNET").</div></p> <p>The next step was to write the PRU microcontroller code to send and receive Ethernet packets. After a lot of testing with the Alto's <em>Ethernet Diagnostic Program</em> (EDP), I was able to echo packets back and forth between the BeagleBone gateway and the Alto.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUKO0rboCyUWZqP7RG09OFy7ke-2vqo-YDdxbAuAwo_to3fhHA6vQsgK7S9q5B752IlnY71KG2CuTSPFhPFIiybt_QJLmxiCg3TQsf81SEBZyEHfdONK-nY7I3R_gtNYSHijhBXpeaMZqb/w9999/edp.jpg"><img alt="The Ethernet Diagnostic Program can be used to test the Ethernet. It has a simple GUI." class="hilite" height="390" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUKO0rboCyUWZqP7RG09OFy7ke-2vqo-YDdxbAuAwo_to3fhHA6vQsgK7S9q5B752IlnY71KG2CuTSPFhPFIiybt_QJLmxiCg3TQsf81SEBZyEHfdONK-nY7I3R_gtNYSHijhBXpeaMZqb/w400/edp.jpg" title="The Ethernet Diagnostic Program can be used to test the Ethernet. It has a simple GUI." width="400" /></a><div class="cite">The Ethernet Diagnostic Program can be used to test the Ethernet. It has a simple GUI.</div></p> <p>To be useful, the gateway must support the network stack: Pup packets, network booting, Alto-style FTP and so forth. I started by rewriting the Alto's network code, making a direct port of the BCPL implementation<span id="fnref:bcpl"><a class="ref" href="#fn:bcpl" rel="footnote">3</a></span> to Python. This turned out to be a mess, because the original implementation depended heavily on the Alto's operating system, which provided multiple threads, so the application could run in one thread and the network code in other threads. I managed to get the stateless low-level Pup packets to work okay, but the higher-level Byte Stream Protocol was a tangle of busy-waiting loops and timeouts.</p> <p>Fortunately the <a href="http://www.livingcomputers.org/">Living Computers Museum+Lab</a> (LCM+L) came to rescue. Josh Dersch at the museum had written a C# implementation of the Alto's network stack, so I decided to discard my implementation of the network stack. This implementation, called IFS,<span id="fnref:ifs"><a class="ref" href="#fn:ifs" rel="footnote">4</a></span> supported the low-level protocols, as well as servers for network operations, FTP, and Copydisk. IFS was a new implementation rather than a direct port like my attempt, and that approach worked much better.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1ZggYDWcax1sAgcWntaM829lh3B3BRQLYZWx9wzj9wkuyHOzw-UJr5-Mn6CIou1PHYOW3eUj0EhDNJUiSSdJmgeqH9gCfoIpwdgwhpFwAmvmqOXqjOpurijuPgXlexMZ0VhymrifZrmfx/w9999/lcm-interface.jpg"><img alt="The Living Computers Museum built a 3 Mb/s Ethernet interface using an FPGA chip." class="hilite" height="290" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1ZggYDWcax1sAgcWntaM829lh3B3BRQLYZWx9wzj9wkuyHOzw-UJr5-Mn6CIou1PHYOW3eUj0EhDNJUiSSdJmgeqH9gCfoIpwdgwhpFwAmvmqOXqjOpurijuPgXlexMZ0VhymrifZrmfx/w400/lcm-interface.jpg" title="The Living Computers Museum built a 3 Mb/s Ethernet interface using an FPGA chip." width="400" /></a><div class="cite">The Living Computers Museum built a 3 Mb/s Ethernet interface using an FPGA chip.</div></p> <p>The LCM+L also built an Ethernet interface to the Alto. Theirs was much more complex than mine, consisting of an FPGA chip on a custom PCI card plugged into a PC. Unlike my interface, theirs communicated with a transceiver box, rather than connecting to the Alto directly. Even though the LCM+L's FPGA interface worked for us, I decided to complete my interface board since I liked the idea of a low-cost, compact Ethernet gateway. Their interface is more "realistic", since it connects to a real transceiver and network cable and can work with multiple Altos on a network. (The photo below shows the mini-network connecting the LCM+L interface and an Alto.) On the other hand not everyone has Ethernet transceivers lying around, so mine is more widely usable.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYjelG_O3YQwENe_9a4YL9lZo7G5opPU0hO5HM8f0HsKGDNCVwPaOWGg4cg6NGH_UmTuBNbLuEM7y32XNBH8MAaENBO3v6Knvrx77PhHziO68V-09tZQyLRW-RJe5Wuyb29vnoEa_ts01e/w9999/network.jpg"><img alt="A very short 3 Mb/s Ethernet network, showing two transceivers attached to the coaxial cable. One transceiver is connected to the Alto and the other is connected to the LCM+L gateway card." class="hilite" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYjelG_O3YQwENe_9a4YL9lZo7G5opPU0hO5HM8f0HsKGDNCVwPaOWGg4cg6NGH_UmTuBNbLuEM7y32XNBH8MAaENBO3v6Knvrx77PhHziO68V-09tZQyLRW-RJe5Wuyb29vnoEa_ts01e/w400/network.jpg" title="A very short 3 Mb/s Ethernet network, showing two transceivers attached to the coaxial cable. One transceiver is connected to the Alto and the other is connected to the LCM+L gateway card." width="400" /></a><div class="cite">A very short 3 Mb/s Ethernet network, showing two transceivers attached to the coaxial cable. One transceiver is connected to the Alto and the other is connected to the LCM+L gateway card.</div></p> <p>I made a simple printed circuit board to replace my breadboarded prototype. This was the first circuit board I had designed in about 35 years and technology has certainly changed. Back in the 1980s, I drew circuit board traces with a resist pen on a copper-clad board, and then etched the board in ferric chloride solution from Radio Shack. Now, I designed my board using Eagle, uploaded the file to OSH Park, and received a beautiful circuit board a few days later.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7x85kdU5HNNO-pBdGOHSbcwx8XOIK7RyumbCodX5b6ZdDUNIhX-5PpDMAGbXCdNQH0nl0De5lSzUKn9HHTuGQGCroKasHhzaVH7gZQGRj36OtkVqksHEGkfGjPIP8DUSjR8ZujeZ5f3I2/w9999/beaglebone-alto-interface.jpg"><img alt="My 3 Mb/s Ethernet interface is a level-shifter card on a BeagleBone. Note the capacitor soldered directly to the driver IC to fix a ringing signal problem." class="hilite" height="231" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7x85kdU5HNNO-pBdGOHSbcwx8XOIK7RyumbCodX5b6ZdDUNIhX-5PpDMAGbXCdNQH0nl0De5lSzUKn9HHTuGQGCroKasHhzaVH7gZQGRj36OtkVqksHEGkfGjPIP8DUSjR8ZujeZ5f3I2/w400/beaglebone-alto-interface.jpg" title="My 3 Mb/s Ethernet interface is a level-shifter card on a BeagleBone. Note the capacitor soldered directly to the driver IC to fix a ringing signal problem." width="400" /></a><div class="cite">My 3 Mb/s Ethernet interface is a level-shifter card on a BeagleBone. Note the capacitor soldered directly to the driver IC to fix a ringing signal problem.</div></p> <p>Running the LCM+L's IFS software on the BeagleBone took some work since the BeagleBone runs Linux and IFS was written in C# for Windows. By using the <a href="http://www.mono-project.com/">Mono</a> platform, I could run most of the C# code on the BeagleBone. However, the LCM+L software stack communicated with the gateway by encapsulating Alto Ethernet packets in a modern Ethernet packet, using a .Net Pcap library to access the raw Ethernet. Unfortunately, this library didn't work with Mono, so I rewrote the IFS encapsulation to use UDP.</p> <p>At this point the Alto and my BeagleBone implementation communicated most of the time, but there were a few tricky bugs to track down. The first problem was FTP would get sometimes bad packets. Eventually I discovered that I had mixed up byte and word counts in one place, and the large packets from FTP were overflowing the PRU's buffer.</p> <p>The next problem was that when I used <em>Copydisk</em> to copy a disk pack from the Alto to the BeagleBone, a dropped packet caused the network to lock up after a couple minutes. This was puzzling since the sender should retransmit the lost packet after a timeout and everything should recover (like TCP). After tedious debugging, I found that if the Alto and the BeagleBone transmitted packets close together, a race condition in my code caused a dropped packet.<span id="fnref:breath"><a class="ref" href="#fn:breath" rel="footnote">5</a></span><span id="fnref:race"><a class="ref" href="#fn:race" rel="footnote">6</a></span> Then IFS neglected to send a necessary ack when it received an unexpected packet, so the Alto kept resending the wrong packet. After fixing both my gateway code and the IFS ack, the network ran without problems.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhx5wSADF3M4fEIn_p9O5I1GJlz3wmeRTGrYbD2ggsJzgiyZNTHroVEBh4ZvJkPJg9RX8h1EIU0PjPLX8lJg2xaeX_XV4byhdX4k1G4iUDNrR9RYLh5iya72Hju01_A47VSaIN7rA0SlecV/w9999/gateway-v2.jpg"><img alt="Second version of the interface. Note the blue jumper wire to replace the missing trace." class="hilite" height="237" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhx5wSADF3M4fEIn_p9O5I1GJlz3wmeRTGrYbD2ggsJzgiyZNTHroVEBh4ZvJkPJg9RX8h1EIU0PjPLX8lJg2xaeX_XV4byhdX4k1G4iUDNrR9RYLh5iya72Hju01_A47VSaIN7rA0SlecV/w400/gateway-v2.jpg" title="Second version of the interface. Note the blue jumper wire to replace the missing trace." width="400" /></a><div class="cite">Second version of the interface. Note the blue jumper wire to replace the missing trace.</div></p> <p>My first version of the PCB had a few issues<span id="fnref:problems"><a class="ref" href="#fn:problems" rel="footnote">8</a></span> so I made a second version (above). I found that the driver chip didn't sink enough current for a long cable, so I replaced it with the chip used by the transceivers (a 7438 open collector NAND gate). I also decided to try KiCad instead of Eagle for the second board. Unfortunately, I made a mistake in KiCad<span id="fnref:kicad"><a class="ref" href="#fn:kicad" rel="footnote">7</a></span> and the new board was missing a trace, so I had to solder in a jumper (which you can seen in the photo above).</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiI3m8xzBR4R4V6mvQ_Vaock42mviMH0Fd-VJpd0cH218gXHYhwrdBMpmRUVCSbgx7VuFuS-I9SFin-1HBJa5adl9BcC2K3DNSzZ5uZWqbdDGIAUzwp05DisvaHNO5v-606CSLdwM7ZA3Sp/w9999/probing-board.jpg"><img alt="I probed the Alto's Ethernet card with an oscilloscope to check the signals it was receiving. An extender card from the LCM+L allowed us to access the card." class="hilite" height="422" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiI3m8xzBR4R4V6mvQ_Vaock42mviMH0Fd-VJpd0cH218gXHYhwrdBMpmRUVCSbgx7VuFuS-I9SFin-1HBJa5adl9BcC2K3DNSzZ5uZWqbdDGIAUzwp05DisvaHNO5v-606CSLdwM7ZA3Sp/w400/probing-board.jpg" title="I probed the Alto's Ethernet card with an oscilloscope to check the signals it was receiving. An extender card from the LCM+L allowed us to access the card." width="400" /></a><div class="cite">I probed the Alto's Ethernet card with an oscilloscope to check the signals it was receiving. An extender card from the LCM+L allowed us to access the card.</div></p> <p>I tested the new board but it didn't work at all: the Alto wasn't receiving data or sending data. I realized that the new driver chip was a NAND gate so the signals were now inverted. I updated the PRU code to flip LOW and HIGH on the data out signal. The board still didn't work, so I probed the Alto's Ethernet board with an oscilloscope, comparing the signals from the old working board to the new failing board. Strangely, both signals were identical in the Alto and looked fine.</p> <p>Eventually Marc asked me if there could be something wrong with the collision detection. I realized that the the new NAND driver was also inverting the collision detection signal. Thus, the Alto was seeing constant network collisions and refused to send or receive anything. After fixing this in my PRU software, the new board worked fine. I'm making a third revision of the board to fix the missing trace; hopefully this won't break something else.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguiZlbhr_SntyGdBLo6vY0HWzUtRKEPeY3GopacpJNyXrKABm7ffdanbSo36HAnT6b3R3pVU1T8MRdaIxYUjGIKS7_m6XRD1JQ9sYKNef1d4qR1PxSh7td3Ah0xEdmRKocgTwnmRyXvQ99/w9999/transceivers.jpg"><img alt="An assortment of vintage Ethernet transceivers, along with the tap tools used to drill holes in the Ethernet cable for the vampire tap connection." class="hilite" height="276" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguiZlbhr_SntyGdBLo6vY0HWzUtRKEPeY3GopacpJNyXrKABm7ffdanbSo36HAnT6b3R3pVU1T8MRdaIxYUjGIKS7_m6XRD1JQ9sYKNef1d4qR1PxSh7td3Ah0xEdmRKocgTwnmRyXvQ99/w400/transceivers.jpg" title="An assortment of vintage Ethernet transceivers, along with the tap tools used to drill holes in the Ethernet cable for the vampire tap connection." width="400" /></a><div class="cite">An assortment of vintage Ethernet transceivers, along with the tap tools used to drill holes in the Ethernet cable for the vampire tap connection.</div></p> <h2>Conclusion</h2> <p>The Ethernet gateway project took much more time and encountered more problems than I expected. But it worked in the end, and several Alto owners are now using my gateway. I've open-sourced this interface (the board layout and the gateway software); it's available on <a href="https://github.com/shirriff/alto-ethernet-interface">github</a>.</p> <p>The Alto I've been restoring came from YCombinator; the restoration team includes Marc Verdiell, <a href="https://rescue1130.blogspot.com/">Carl Claunch</a> and Luca Severini. My full set of Alto posts is <a href="http://www.righto.com/search/label/alto">here</a> and Marc's extensive videos of the restoration are <a href="https://www.youtube.com/user/mverdiell/videos">here</a>. Thanks to the <a href="http://www.livingcomputers.org/">Living Computers Museum+Labs</a> for the <a href="https://github.com/livingcomputermuseum/IFS">IFS software</a>.</p> <p>Follow me on <a href="https://twitter.com/kenshirriff">Twitter</a> or <a href="http://www.righto.com/feeds/posts/default">RSS</a> to find out about my latest blog posts.</p> <h2>Notes and references</h2> <div class="footnote"> <ol> <li id="fn:pup"> <p>For more information on the Pup protocol, see <a href="http://bitsavers.trailing-edge.com/pdf/xerox/alto/ethernet/pupArch.pdf">Pup: An Internetwork Architecture</a> and the <a href="http://www.textfiles.com/bitsavers/pdf/xerox/alto/pupSpec.pdf">Pup Specifications</a> memo.  <a class="footnote-backref" href="#fnref:pup" rev="footnote" title="Jump back to footnote 1 in the text">↩</a></p> </li> <li id="fn:pru"> <p>Programming the PRU microcontrollers has a difficult learning curve, and it's not nearly as well documented as, say, the Arduino. Based on my experience with the PRU, I wrote some programming tips <a href="http://www.righto.com/2016/08/pru-tips-understanding-beaglebones.html">here</a> and <a href="http://www.righto.com/2016/09/how-to-run-c-programs-on-beaglebones.html">here</a>. <a class="footnote-backref" href="#fnref:pru" rev="footnote" title="Jump back to footnote 2 in the text">↩</a></p> </li> <li id="fn:bcpl"> <p>The Alto's network code is <a href="http://xeroxalto.computerhistory.org/Indigo/AltoSource/PUPSOURCES.DM!3_">online</a>; you can look at one of the Pup files <a href="http://xeroxalto.computerhistory.org/Indigo/AltoSource/PUPSOURCES.DM!3_/.PupBSPOpenClose.bcpl.html">here</a>. The code is written in BCPL, which was a predecssor to C. It is very similar to C, but with different syntactic choices. For instance, <code>>></code> is not a shift but accesses a field in a structure. <a class="footnote-backref" href="#fnref:bcpl" rev="footnote" title="Jump back to footnote 3 in the text">↩</a></p> </li> <li id="fn:ifs"> <p>At PARC, IFS was an acronym for <em>Interim File System</em>, an Alto-based distributed file server. It was called <em>interim</em> because an improved system was being developed, but somehow a new system never replaced IFS. <a class="footnote-backref" href="#fnref:ifs" rev="footnote" title="Jump back to footnote 4 in the text">↩</a></p> </li> <li id="fn:breath"> <p>Most of the time, the BeagleBone and the Alto alternated sending packets. But every second, IFS sent a "breath of life" packet, the packet executed by the Alto to start a network boot. The breath of life packet was part of the original Alto—it simplified the network boot code since the Alto didn't need to request a network boot, but just listen for a second or two. Since the breath of life packet was asynchronous with respect to the other network traffic, eventually it would happen at a bad time for my code, triggering the dropped packet problem. <a class="footnote-backref" href="#fnref:breath" rev="footnote" title="Jump back to footnote 5 in the text">↩</a></p> </li> <li id="fn:race"> <p>The problem with the PRU and the "breath of life" packet was due to how I was sending signals between the PRU and the main BeagleBone processor. When sending a packet, the main processor would signal the PRU, and then wait for a signal back when the packet was sent. When a packet was received, the PRU would send a signal to the main processor. The problem was that the PRU sent the same signal in both cases. So a "packet received" signal at the wrong time could wake up the packet sending code, losing the received packet. Fundamentally, I was treating the signals between the main processor and the PRU as synchronous, when everything was really asynchronous. I rewrote the gateway code so ownership of the send and receive buffers was explicitly transferred between the main processor and the PRU. A signal just indicated that ownership had changed somehow; checking the buffer status showed what exactly had changed. See <a href="https://groups.google.com/forum/#!msg/beagleboard/3sre2nT-dAc/YWXWFFXOBQAJ">this discussion</a> for details. <a class="footnote-backref" href="#fnref:race" rev="footnote" title="Jump back to footnote 6 in the text">↩</a></p> </li> <li id="fn:kicad"> <p>My error in KiCad was I placed a net label just a bit too far from the wire on the schematic, so the wire wasn't connected to the net. <a class="footnote-backref" href="#fnref:kicad" rev="footnote" title="Jump back to footnote 7 in the text">↩</a></p> </li> <li id="fn:problems"> <p>My first PCB had a couple issues that I had to hack around. Ringing in the signal to the Alto corrupted it, so I added a damping capacitor. The driver didn't have enough current for an Ethernet cable longer than 10 feet, so I added a pull-down resistor. There were also a couple mechanical issues. The location of the Ethernet jack made it hard to remove the cable, and the board blocked one of the BeagleBone buttons. I also discovered that using a 74HC125 driver chip didn't work at all; just the 74AHCT125 worked. <a class="footnote-backref" href="#fnref:problems" rev="footnote" title="Jump back to footnote 8 in the text">↩</a></p> </li> </ol> </div> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/6264947694886887540/1182972412801248728' onclick=''> 7 comments: </a> </span> <span class='post-icons'> <span class='item-action'> <a href='https://www.blogger.com/email-post/6264947694886887540/1182972412801248728' title='Email Post'> <img alt='' class='icon-action' height='13' src='http://img1.blogblog.com/img/icon18_email.gif' width='18'/> </a> </span> <span class='item-control blog-admin pid-1138732533'> <a href='https://www.blogger.com/post-edit.g?blogID=6264947694886887540&postID=1182972412801248728&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <span class='post-backlinks post-comment-link'> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=1182972412801248728&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=1182972412801248728&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=1182972412801248728&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=1182972412801248728&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=1182972412801248728&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'><span class='post-labels'> Labels: <a href='http://www.righto.com/search/label/alto' rel='tag'>alto</a>, <a href='http://www.righto.com/search/label/beaglebone' rel='tag'>beaglebone</a> </span> </div> <div class='post-footer-line post-footer-line-3'></div> </div> </div> </div> </div></div> <div class="date-outer"> <div class="date-posts"> <div class='post-outer'> <div class='post hentry' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIytCKLdDD5HbybbEsOzcrV06_86i_J57B76XU7yw6n-3wcho9ErRoGLvqh_ftA7oSH-WFFGCZX0jYbZeimiixlbQ7W355I_lxSFaOUnrG2JhJkXuSS-c85ho5UHv6hFdxp23b5jEpaRWO/w200/alto-mandelbrot-full.jpg' itemprop='image_url'/> <meta content='6264947694886887540' itemprop='blogId'/> <meta content='352331206319530922' itemprop='postId'/> <a name='352331206319530922'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://www.righto.com/2018/01/xerox-alto-zero-day-cracking-disk.html'>Xerox Alto zero-day: cracking disk password protection on a 45 year old system</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-352331206319530922' itemprop='description articleBody'> <style> code {background-color:#eee;font-size:80%;} </style> <p>We've been archiving a bunch of old Xerox Alto disk packs from the 1970s. A few of them turned out to be password-protected, so I needed to figure out how to get around the password protection. I've developed a way to disable password protection, as well as a program to find the password instantly. (This attack is called <i>XeroDay</i>, based on a suggestion by <a href="https://news.ycombinator.com/item?id=16073896">msla</a>.)</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIytCKLdDD5HbybbEsOzcrV06_86i_J57B76XU7yw6n-3wcho9ErRoGLvqh_ftA7oSH-WFFGCZX0jYbZeimiixlbQ7W355I_lxSFaOUnrG2JhJkXuSS-c85ho5UHv6hFdxp23b5jEpaRWO/w9999/alto-mandelbrot-full.jpg"><img alt="The Xerox Alto. The disk drive is the black unit below the keyboard. The processor is behind the grill. The Mandelbrot set has nothing to do with this article." class="hilite" height="413" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIytCKLdDD5HbybbEsOzcrV06_86i_J57B76XU7yw6n-3wcho9ErRoGLvqh_ftA7oSH-WFFGCZX0jYbZeimiixlbQ7W355I_lxSFaOUnrG2JhJkXuSS-c85ho5UHv6hFdxp23b5jEpaRWO/w200/alto-mandelbrot-full.jpg" title="The Xerox Alto. The disk drive is the black unit below the keyboard. The processor is behind the grill. The Mandelbrot set has nothing to do with this article." width="200" /></a><div class="cite">The Xerox Alto. The disk drive is the black unit below the keyboard. The processor is behind the grill. The Mandelbrot set has nothing to do with this article.</div></p> <p>The Alto was a revolutionary computer designed at Xerox PARC in 1973 to investigate personal computing. In the photo above, the Alto computer itself is in the lower cabinet. The Diablo disk drive (in 1970s orange, below the keyboard) takes a removable 14 inch disk pack that stores 2.5 megabytes of data. (A bunch of disk packs are visible behind the Alto and in the photo below.) I've been restoring a Xerox Alto, along with Marc Verdiell, Luca Severini and <a href="https://rescue1130.blogspot.com/">Carl Claunch</a>. (The full set of Alto posts is <a href="http://www.righto.com/search/label/alto">here</a> and Marc's videos are <a href="https://www.youtube.com/user/mverdiell/videos">here</a>.)</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisHjpFZIDw5JJn1OI02CdzelPSmK5SmSN68pmbX4hdsPciIk8Pgi2AiubEgWcj6XQDiMh4m-4kCYIS7vbdhrkSlCQkIpXnH0N8FLMmJqn6Ics9KznGVaOdkKT_H2IfDjBTLERnQERchuqS/w9999/parc-disks.jpg"><img alt="Some of the disks from Xerox PARC that we're archiving." class="hilite" height="309" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisHjpFZIDw5JJn1OI02CdzelPSmK5SmSN68pmbX4hdsPciIk8Pgi2AiubEgWcj6XQDiMh4m-4kCYIS7vbdhrkSlCQkIpXnH0N8FLMmJqn6Ics9KznGVaOdkKT_H2IfDjBTLERnQERchuqS/w400/parc-disks.jpg" title="Some of the disks from Xerox PARC that we're archiving." width="400" /></a><div class="cite">Some of the disks from Xerox PARC that we're archiving.</div></p> <p>Now that we have the Alto running, one project is to archive a bunch of disks that have been sitting at Xerox PARC for decades, and find out if there are any interesting treasures among the disks. We can archive disks by running the <em>Copydisk</em> program on the Alto, and copying them over Ethernet to a <a href="https://github.com/livingcomputermuseum/IFS">PC server</a>. (Ethernet was invented by Xerox for the Alto.) However, it's considerably faster to read the data directly off the disk drive, bypassing the computer. Carl created an FPGA-based disk controller (below) that connects to the Diablo disk drive, speeding up the archiving process.<span id="fnref:carl"><a class="ref" href="#fn:carl" rel="footnote">1</a></span></p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpgAEyir_C8OidFaLiJThhuXOa2MiYCL-_Ei6d19Z8GucwyYjYpHlPW-IARsuSRC2r7GLFnFYRdI0YySa0-1A3KQ_hQtLrdxpQwqe6oOmEl6Z1Cy7b4dKFER-yboCudqfLa7wxew3snEh6/w9999/disk-tool.jpg"><img alt="Diablo disk tool, built by Carl Claunch using an FPGA." class="hilite" height="171" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpgAEyir_C8OidFaLiJThhuXOa2MiYCL-_Ei6d19Z8GucwyYjYpHlPW-IARsuSRC2r7GLFnFYRdI0YySa0-1A3KQ_hQtLrdxpQwqe6oOmEl6Z1Cy7b4dKFER-yboCudqfLa7wxew3snEh6/w400/disk-tool.jpg" title="Diablo disk tool, built by Carl Claunch using an FPGA." width="400" /></a><div class="cite">Diablo disk tool, built by Carl Claunch using an FPGA.</div></p> <p>Before reading each disk, we open up the pack and carefully clean the surface. After storage for decades, these disks have some grime, dust, and the occasional bug (of the dead insect variety), so we need to clean them to reduce the chance of a head crash.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhExjUI86wpeKzsnlw2lOD1914RB0epVhwvN_ib1AufFmoyZdF1LDJ7mBodVajgsYns7RsDZNm7YWwaJUTdPzcQaPF_VzhaKcSsGwZlgNZC_I5NNbewk1RtbhMozdUZka7o644XbTep4Gic/w9999/opened-disk.jpg"><img alt="A Xerox Alto disk pack, opened for cleaning. The "flaws" on the surface are just reflections." class="hilite" height="285" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhExjUI86wpeKzsnlw2lOD1914RB0epVhwvN_ib1AufFmoyZdF1LDJ7mBodVajgsYns7RsDZNm7YWwaJUTdPzcQaPF_VzhaKcSsGwZlgNZC_I5NNbewk1RtbhMozdUZka7o644XbTep4Gic/w400/opened-disk.jpg" title="A Xerox Alto disk pack, opened for cleaning. The "flaws" on the surface are just reflections." width="400" /></a><div class="cite">A Xerox Alto disk pack, opened for cleaning. The "flaws" on the surface are just reflections.</div></p> <p>Most of the archived disks can be booted on the Alto or the <a href="https://github.com/livingcomputermuseum/ContrAlto">ContrAlto simulator</a>. But a few disks only booted to a password prompt (see below), and we couldn't use the disk without the password. So I decided to hack my way into the password-protected disks.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZZKKTh0j_RVn0V5lkyzRrNIUcJz7O8M4aRJccJt46vPT1oYHbdaiUBup9RqeDjhZgS7Wdx9CX2Kwp8GMFE6ETbWMnMLBX4XS0YVJpQGc_mggzWwojr_38lpSRZUOu33ktq9V0B_0-61HE/w9999/password-screen.png"><img alt="Booting a password-protected disk results in a request for the password." class="hilite" height="36" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZZKKTh0j_RVn0V5lkyzRrNIUcJz7O8M4aRJccJt46vPT1oYHbdaiUBup9RqeDjhZgS7Wdx9CX2Kwp8GMFE6ETbWMnMLBX4XS0YVJpQGc_mggzWwojr_38lpSRZUOu33ktq9V0B_0-61HE/w442/password-screen.png" title="Booting a password-protected disk results in a request for the password." width="442" /></a><div class="cite">Booting a password-protected disk results in a request for the password.</div></p> <p>The Alto documentation discusses password protection, explaining how a password can be associated with a disk. It only promises "a modest level of security", which turns out to be true. It also says if you forget the password, "you will need an expert to get access to anything on your disk." But could I break in without finding an expert?</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmDOGWE1VRyvaV8FrnWMkmMttxLzRTRH3tcdDQRLl_1Z_sXf1tIXuV18Abc2PlB5xtWfTB5AGcFtCc_i50d6qMVdvBjSn0C_5NV8VgcsPBj4oQAULMQhgLgTqtI0FLnJqaeNvLV3L65zWm/w9999/users-manual.png"><img alt="Password protection is described in the Alto User's Handbook page 5." class="hilite" height="91" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmDOGWE1VRyvaV8FrnWMkmMttxLzRTRH3tcdDQRLl_1Z_sXf1tIXuV18Abc2PlB5xtWfTB5AGcFtCc_i50d6qMVdvBjSn0C_5NV8VgcsPBj4oQAULMQhgLgTqtI0FLnJqaeNvLV3L65zWm/w650/users-manual.png" title="Password protection is described in the Alto User's Handbook page 5." width="650" /></a><div class="cite">Password protection is described in the <a href="http://bitsavers.org/pdf/xerox/alto/Alto_Users_Handbook_Sep79.pdf">Alto User's Handbook</a> page 5.</div></p> <h2>A bit about passwords</h2> <p> Storing passwords in plain text is a very bad idea, since anyone who can access the file can see the password.<span id="fnref:zero"><a class="ref" href="#fn:zero" rel="footnote">9</a></span> Most systems use a solution invented by <a href="https://en.wikipedia.org/wiki/Roger_Needham">Roger Needham</a> in 1967. Instead of storing the password, you hash the password through a cryptographic one-way function and store the hash. When the user inputs a password, you hash it through the same function and compare the hashes. If they match, the passwords match. And if anyone sees the hash, there's no easy way to get the password back. </p> <p>One problem with hashed passwords is if two users have the same hash, then you know they have the same password. A solution (invented in Unix) is to hash some random bytes (called <a href="https://en.wikipedia.org/wiki/Salt_(cryptography)">salt</a>) along with the password to yield the stored hash. Since different users will have different salt, the hashes will be different even if the passwords are the same. (Of course you need to store the salt along with the hash in order to check passwords.)<span id="fnref:rainbow"><a class="ref" href="#fn:rainbow" rel="footnote">2</a></span> Like Unix, the Alto used salted and hashed passwords.</p> <h2>The Alto's hash algorithm</h2> <p>The source code for the Alto's password algorithm reveals how the password hashing is implemented.<span id="fnref:passwordCode"><a class="ref" href="#fn:passwordCode" rel="footnote">3</a></span> The Alto uses four words of salt with the password (two words based on the password creation time and two words based on the user name). The password hash is 4 words (64 bits) long. The Alto's password hash algorithm is pretty simple:<span id="fnref:negate"><a class="ref" href="#fn:negate" rel="footnote">4</a></span></p> <p><code>Hash c = -a*x*x + b*y</code></p> <p>where <code>a</code> is the time salt and <code>b</code> is the user name salt. <code>x</code> is a one-word value generated from the password string and <code>y</code> is a two-word value from the password string, both generated by concatenating characters from the password.<span id="fnref:concat"><a class="ref" href="#fn:concat" rel="footnote">5</a></span></p> <h2>Disabling the password</h2> <p>There's a way to disable the password on disk, gaining access to the file system.<span id="fnref:neptune"><a class="ref" href="#fn:neptune" rel="footnote">6</a></span> The Alto boots from disk by running the file <code>sys.boot</code>; this file decides if a password is required for boot, based on the 9-word password vector stored inside the file. The first word is a flag indicating if the disk is password protected. If the password flag is set, the boot program requires a password before proceeding. The next four words are the salt, and the final four words are the password hash itself.</p> <p>The password protection can be disabled by clearing the flag word inside <code>sys.boot</code>, which is the 128th word in the second block of <code>sys.boot</code>. The tricky part is finding where this word is on disk. The file system stores a directory as the name of each file along with the disk address of the file's first block. By reading the directory as raw data and interpreting it, we can find the location of <code>sys.boot</code>. In the Alto file system, each disk block has pointers to the previous and next block. So once we've found the first block, we can follow the pointer to find the second block. (Basically I re-implemented a subset of the Alto file system using the raw disk.) Erasing the password flag in this block makes the disk bootable without the password.</p> <p>After implementing this, I realized there's a short cut. The writers of the disk bootstrap code didn't want to re-implement the file system either, so the Alto simply copies the first block of <code>sys.boot</code> to the first disk sector. This makes it trivial to find the file, without needing to scan the directory. Once I have the first block, I can find the second block from the pointer, access the block, and clear the password flag, disabling the security.<span id="fnref:filesystem"><a class="ref" href="#fn:filesystem" rel="footnote">7</a></span></p> <p>I made a simple Python program to update the disk image file and clear the password flag (<a href="https://gist.github.com/shirriff/0faa98f7c0740583f04bbf8425c544ce">link</a>). After running this program, I was able to access the protected disks. The password-protected disks didn't have any super-secret treasures. However, one disk contained an implementation of APL in Mesa, which was interesting. (<a href="https://en.wikipedia.org/wiki/APL_(programming_language)">APL</a> is a cool programming language known for its extremely terse notation and strange character set. <a href="https://en.wikipedia.org/wiki/Mesa_(programming_language)">Mesa</a> is a high-level language developed at Xerox PARC; it influenced Java.) We haven't gotten Mesa running on the Alto yet, but this looks like an interesting thing to try out.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtxjh4DToX_z0v2WCvnqmK8X362kOMpOoR-0CjSRGT4r1xJN82M7GUlKkRoAeIJ4aeEJzNJvStvptMzdHQ786dNSlXovSEkx80iQn5Yq9wOP-Z3OUG5P2JK1XkmeWqESx_XpuXPJynWS05/w9999/apl.png"><img alt="After defeating the password, I can view the disk contents. These files implement APL in Mesa." class="hilite" height="271" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtxjh4DToX_z0v2WCvnqmK8X362kOMpOoR-0CjSRGT4r1xJN82M7GUlKkRoAeIJ4aeEJzNJvStvptMzdHQ786dNSlXovSEkx80iQn5Yq9wOP-Z3OUG5P2JK1XkmeWqESx_XpuXPJynWS05/w606/apl.png" title="After defeating the password, I can view the disk contents. These files implement APL in Mesa." width="606" /></a><div class="cite">After defeating the password, I can view the disk contents. These files implement APL in Mesa.</div></p> <h2>Brute-forcing the password</h2> <p>While I could access the disk simply by clearing the password flag, I wondered what the original passwords were. I implemented the password algorithm in C (<a href="https://gist.github.com/shirriff/e333b99b521bd8dbddbbd40868245011">link</a>), so I could rapidly test passwords. My hope was that testing against a list of <a href="https://github.com/danielmiessler/SecLists/tree/master/Passwords">top 100,000 passwords</a> would find the passwords, since I didn't expect much in the way of 1970s password security practices. Surprisingly, there were no hits so the passwords weren't common words. My next step was brute-forcing the password by generating all strings of length 1, 2, 3 and so forth.<span id="fnref:lowercase"><a class="ref" href="#fn:lowercase" rel="footnote">8</a></span> Finally at length 8, I cracked the first password with "AATFDAFD". The second disk had password "HGFIHD" and the third had "AAJMAKAY". Apparently random strings were popular passwords back then.</p> <p>I was a bit suspicious when I saw that both 8-character passwords started with "AA" so I investigated a bit more. It turned out that using "AB" in place of "AA" also worked, as did starting with anything in "{A-Z}{A-G}". Studying the algorithm more closely, I realized that when <code>x</code> and <code>y</code> get too long, the old character bits were just dropped. Thus, when you use a password longer than 6 characters, most of the bits from the first characters are lost. This is a pretty big flaw in the algorithm.</p> <h2>Finding the password with math</h2> <p>It takes half an hour or so to brute force the password; can we do better? Yes, by doing some algebra on the password formula yielding:</p> <p><code>y = (c + a*x*x) / b</code></p> <p>where <code>x</code> and <code>y</code> are generated from the password string, <code>a</code> and <code>b</code> are salt, and <code>c</code> is the stored password hash. Since <code>x</code> is only 16 bits, we can easily try all the values, finding ones for which the division works. When we find a solution for <code>y</code>, we can recover the original password by chopping <code>x</code> and <code>y</code> into 7-bit characters. Using this technique, the password can be recovered almost instantly. I implemented this in Python <a href="https://gist.github.com/shirriff/978cd9a345870f7aa96234a2884c6321">here</a>.</p> <h2>Conclusion</h2> <p>The Xerox Alto's disk passwords can be trivially bypassed, and the password can be easily recovered. The password algorithm has multiple flaws that make it weaker than you'd expect (dropping password characters) and easily reversed. Since the system is almost 45 years old, they had to keep the code small and they weren't facing modern threats. After all, Xerox only promised "modest" security with the passwords, and that's what it provided.</p> <h2>Notes and references</h2> <div class="footnote"> <ol> <li id="fn:carl"> <p>For more details on the archiving process, see <a href="https://rescue1130.blogspot.com/2017/12/worked-on-roomba-archived-large-batch.html">Carl's post on archiving</a>. He writes about the FPGA disk tool <a href="https://rescue1130.blogspot.com/2017/06/refactoring-and-ruggedizing-my-fpga.html?m=0">here</a>. <a class="footnote-backref" href="#fnref:carl" rev="footnote" title="Jump back to footnote 1 in the text">↩</a></p> </li> <li id="fn:rainbow"> <p>Salting passwords also protects against password attacks using precomputed <a href="https://en.wikipedia.org/wiki/Rainbow_table">rainbow tables</a>, but that wasn't a concern back then. <a class="footnote-backref" href="#fnref:rainbow" rev="footnote" title="Jump back to footnote 2 in the text">↩</a></p> </li> <li id="fn:passwordCode"> <p>The password code can be viewed at <a href="http://xeroxalto.computerhistory.org/Indigo/AltoSource/OSSOURCES.DM!2_/.Password.bcpl.html">Password.bcpl</a>. The code is in BCPL, which is a predecessor of C. The syntax has some trivial but confusing differences; I'll explain the most important. <code>p!1</code> is just an array access, equivalent to <code>p[1]</code> in C. <code>vec 4</code> allocates 4 words, essentially <code>malloc(4)</code>. <code>ps>>String.char↑i</code> is equivalent to <code>ps->String.char[i]</code>, accessing a character from the password structure. <code>$a</code> is <code>'a'</code> and <code>rem</code> is <code>%</code>. Square brackets in BCPL are blocks, like curly braces in C. Also note that the code has inline assembly for the vector addition and multiplication functions. <a class="footnote-backref" href="#fnref:passwordCode" rev="footnote" title="Jump back to footnote 3 in the text">↩</a></p> </li> <li id="fn:negate"> <p>The negation in the hash function is broken; only the top two words are negated. The <a href="http://xeroxalto.computerhistory.org/Indigo/AltoSource/OSSOURCES.DM!2_/.Password.bcpl.html">Password.bcpl</a> code points out this bug, but notes that they couldn't fix it without invalidating all the existing passwords. <a class="footnote-backref" href="#fnref:negate" rev="footnote" title="Jump back to footnote 4 in the text">↩</a></p> </li> <li id="fn:concat"> <p>The <code>x</code> value is generated by concatenating the 1st, 4th, ... characters of the password, while <code>y</code> consists of the other characters. The concatenation is done using 7-bit characters, for some reason. <a class="footnote-backref" href="#fnref:concat" rev="footnote" title="Jump back to footnote 5 in the text">↩</a></p> </li> <li id="fn:neptune"> <p>I thought I could boot off an unprotected disk and then use the <em>Neptune</em> graphical file browser to view protected files in the second drive. However, they thought of this and <em>Neptune</em> also checks for a password. In the screenshot below, <em>Neptune</em> shows the contents of the left disk, but requires a password to show the contents of the right disk. <a class="footnote-backref" href="#fnref:neptune" rev="footnote" title="Jump back to footnote 6 in the text">↩</a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmUSmR9S2dlIRCwRMPvisEeD_Iyi6yFTUOvE-4riPsZRmMuRFKAIRX910uG01aIFXcTN96zrO_uUKmEbqYa82xPgVlGre-yPRnbTJemNpCI8PeGChGzlmv24KuuxoSaonlT2EAvB1yn-mf/w9999/neptune.png"><img alt="The Neptune file browser checks for a password." class="hilite" height="270" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmUSmR9S2dlIRCwRMPvisEeD_Iyi6yFTUOvE-4riPsZRmMuRFKAIRX910uG01aIFXcTN96zrO_uUKmEbqYa82xPgVlGre-yPRnbTJemNpCI8PeGChGzlmv24KuuxoSaonlT2EAvB1yn-mf/w467/neptune.png" title="The Neptune file browser checks for a password." width="467" /></a><div class="cite">The Neptune file browser checks for a password.</div></p> </li> <li id="fn:filesystem"> <p>A few more details about the Alto file system for reference. Each disk sector consists of a 2-word header, an 8-word label, and a 256-word data record, each with a checksum. (The Alto's file system (like the Alto) uses 16-bit little-endian words.) The file system structures are defined in include file <a href="http://xeroxalto.computerhistory.org/_cd8_/alto/.altofilesys.d!2.html">AltoFileSys.D</a>. The header contains the physical disk address of the sector (sector number, track number, head number), which is used to validate that the sector returned from the drive is the correct sector. The label contains file system information: pointers to the next and previous sectors in the file, the number of characters used and the file id. This information can also be used to recover from corruption using the <em>scavenger</em> program, which is similar to Unix's <em>fsck</em>. See the <a href="http://bitsavers.org/pdf/xerox/alto/memos_1975/Alto_Operating_System_Reference_Manual_Jun75.pdf">Operating System Reference Manual</a>; section 4.2 describes disk files. <a class="footnote-backref" href="#fnref:filesystem" rev="footnote" title="Jump back to footnote 7 in the text">↩</a></p> </li> <li id="fn:lowercase"> <p>The Alto's password algorithm converted all lower case letters to upper case, which reduced the search space. I'm not sure if special characters are allowed or not. <a class="footnote-backref" href="#fnref:lowercase" rev="footnote" title="Jump back to footnote 8 in the text">↩</a></p> </li> <li id="fn:zero"> <p>The <a href="http://xeroxalto.computerhistory.org/Indigo/AltoSource/OSSOURCES.DM!2_/.Install.bcpl.html">code</a> that calls the password routine has comments about making sure the cleartext password never gets stored on disk, and the in-memory password buffers are zeroed out so they don't get swapped to disk. So it's clear that the writers of the password code were thinking things through. <a class="footnote-backref" href="#fnref:zero" rev="footnote" title="Jump back to footnote 9 in the text">↩</a></p> </li> </ol> </div> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/6264947694886887540/352331206319530922' onclick=''> 19 comments: </a> </span> <span class='post-icons'> <span class='item-action'> <a href='https://www.blogger.com/email-post/6264947694886887540/352331206319530922' title='Email Post'> <img alt='' class='icon-action' height='13' src='http://img1.blogblog.com/img/icon18_email.gif' width='18'/> </a> </span> <span class='item-control blog-admin pid-1138732533'> <a href='https://www.blogger.com/post-edit.g?blogID=6264947694886887540&postID=352331206319530922&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <span class='post-backlinks post-comment-link'> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=352331206319530922&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=352331206319530922&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=352331206319530922&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=352331206319530922&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=352331206319530922&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'><span class='post-labels'> Labels: <a href='http://www.righto.com/search/label/alto' rel='tag'>alto</a> </span> </div> <div class='post-footer-line post-footer-line-3'></div> </div> </div> </div> </div></div> </div> <div class='blog-pager' id='blog-pager'> <span id='blog-pager-older-link'> <a class='blog-pager-older-link' href='http://www.righto.com/search/label/alto?updated-max=2018-01-04T10:00:00-08:00&max-results=20&start=4&by-date=false' id='Blog1_blog-pager-older-link' title='Older Posts'>Older Posts</a> </span> <a class='home-link' href='http://www.righto.com/'>Home</a> </div> <div class='clear'></div> </div></div> </div> </div> <div class='column-left-outer'> <div class='column-left-inner'> <aside> </aside> </div> </div> <div class='column-right-outer'> <div class='column-right-inner'> <aside> <div class='sidebar section' id='sidebar-right-1'><div class='widget HTML' data-version='1' id='HTML2'> <div class='widget-content'> <style> @import url('https://fonts.googleapis.com/css?family=Montserrat:300,400,500,700'); .form-preview { display: flex; flex-direction: column; justify-content: center; margin-top: 30px; padding: clamp(17px, 5%, 40px) clamp(17px, 7%, 50px); max-width: 350px; min-height: 200px; border-radius: 6px; box-shadow: 0 5px 25px rgba(34, 60, 47, 0.25); } .form-preview, .form-preview *{ box-sizing: border-box; } .form-preview .preview-heading { width: 100%; } .form-preview .preview-heading h5{ margin-top: 0; margin-bottom: 0; } .form-preview .preview-input-field { margin-top: 20px; width: 100%; } .form-preview .preview-input-field input { width: 100%; height: 40px; border-radius: 6px; border: 2px solid #e9e8e8; background-color: #fff; outline: none; } .form-preview .preview-input-field input::placeholder, .form-preview .preview-input-field input { opacity: 0.5; color: #000; font-family: "Montserrat"; font-size: 14px; font-weight: 500; line-height: 20px; text-align: center; } .form-preview .preview-submit-button { margin-top: 10px; width: 100%; } .form-preview .preview-submit-button button { width: 100%; height: 40px; border: 0; border-radius: 6px; line-height: 0px; } .form-preview .preview-submit-button button:hover { cursor: pointer; } </style><form data-v-4c58e686="" action="https://api.follow.it/subscription-form/U3NBTmZKVkI1YVpCa000a0RCZHFiQ3FYMko1cWRTZTN6K3hJdWM2QWxJbE1uVXdXUHZZVzJVQzVLZGh5Y0RCVXB2d2JSTzBobGhuY0FsZnlHbVdFZ2VTN2Q4Vy84RnIxUTgzVlcrbXNIR0Y0aW93d3REM2J6VS9RL0gxWURnV1d8ZWN0YStwUWdWWUFiOTIyWDVGWjdYYVdGZEVNcC9qODZacjlwWXRIcEJQRT0=/8" method="post"><div data-v-4c58e686="" class="form-preview" style="background-color: rgb(255, 255, 255); border-style: solid; border-width: 1px; border-color: rgb(204, 204, 204); position: relative;"><div data-v-4c58e686="" class="preview-heading"><h5 data-v-4c58e686="" style="font-family: Montserrat; font-weight: bold; color: rgb(0, 0, 0); font-size: 12px; text-align: center;">Get new posts by email:</h5></div> <div data-v-4c58e686="" class="preview-input-field"><input data-v-4c58e686="" type="email" name="email" placeholder="Enter your email" spellcheck="false" /></div> <div data-v-4c58e686="" class="preview-submit-button"><button data-v-4c58e686="" type="submit" style="font-family: Montserrat; font-weight: bold; color: rgb(255, 255, 255); font-size: 12px; text-align: center; background-color: rgb(0, 0, 0);">Subscribe</button></div></div></form> </div> <div class='clear'></div> </div><div class='widget HTML' data-version='1' id='HTML3'> <h2 class='title'>About the site</h2> <div class='widget-content'> <a href="https://www.righto.com/p/index.html">Contact info and site index</a> </div> <div class='clear'></div> </div><div class='widget PopularPosts' data-version='1' id='PopularPosts1'> <h2>Popular Posts</h2> <div class='widget-content popular-posts'> <ul> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2025/03/pentium-multiplier-adder-reverse-engineered.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_tkseCQFjvlCRwxXp7zEx6KNAZ8xNIWVuoGfCfN1TNp0StUruXNYuoDMDREOy8rXCifwoz8MSOuc8YbWevbKRO-KEEprrEb-wgZeb073Te_rUglEYk3Nv2ENNzexIJ5K8Wh4N-j3lBIFbG6=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2025/03/pentium-multiplier-adder-reverse-engineered.html'>The Pentium contains a complicated circuit to multiply by three</a></div> </div> <div style='clear: both;'></div> </li> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2025/03/mother-of-all-demos-usb-keyset-interface.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_tJVh0X2UkKn5_LMjxg1i3QKr29ictqszD4vDCOBpQvbPCLuLl_S7iqGJBa5cc6OeReU2S8BcYs3Nqw1Obgwmw8W2uM1UOs0uLjSt_XyGPidHNL4z-MOmhVEjYTeiU94yE=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2025/03/mother-of-all-demos-usb-keyset-interface.html'>A USB interface to the "Mother of All Demos" keyset</a></div> </div> <div style='clear: both;'></div> </li> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2024/05/blog-post.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_sD4E8foO0w-bxJrjwmnG_kRdmf2qIo8762aUbOoiCYsH-o0ZVN2cayiYqp5h6f-rt1qmDr27Wzle_kUd3AkdC7FUv9koLsWtBYn881LEqkeFoikJbFZemuXvhQ7l1bKxr4ODmVXKXPwiiIzXKkXdGN=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2024/05/blog-post.html'>Inside a vintage aerospace navigation computer of uncertain purpose</a></div> </div> <div style='clear: both;'></div> </li> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_uxOr43fBuYnlJixtk7X-1YRkmfNxPhqTtczDV3nrF2PV1ZLLApODVQfl8zTwK0PDZ8g8aFqgJWd0RtliBiniTRI8THvK_QDL4-Vw77Wbp-woA=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html'>A Multi-Protocol Infrared Remote Library for the Arduino</a></div> </div> <div style='clear: both;'></div> </li> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2012/05/apple-iphone-charger-teardown-quality.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_vN2XZZIfMSTHGYCzgWlKYxvUIj-TZH1Lxm4GCQTiZ3thearti295K1qK1PcYyrTLuSXSaIwjU2688QRiJD00klieNUIPQUVpw6pd8HJC1Rgquob2jr4gfLj-AofMuiuhRVExkLakWUO7e_Gcea31T8Ra4=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2012/05/apple-iphone-charger-teardown-quality.html'>Apple iPhone charger teardown: quality in a tiny expensive package</a></div> </div> <div style='clear: both;'></div> </li> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2012/10/a-dozen-usb-chargers-in-lab-apple-is.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_vhUSrK5tqnIHLwOBFn8k3MrQC1NKoPqHZe2EON0H_c8m4ucERCeI-ADuacXFRw0uhzsQUdU3znwAiUerixYOqThv5dPjv2EgP2E98qedUuXbvzO0jxAHhFrJIjqeE=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2012/10/a-dozen-usb-chargers-in-lab-apple-is.html'>A dozen USB chargers in the lab: Apple is very good, but not quite the best</a></div> </div> <div style='clear: both;'></div> </li> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2014/09/mining-bitcoin-with-pencil-and-paper.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_uMhWZNZ14SHytQdRdjrvsZxNmdWED9pw4fGd4jj6qiP8DsU2WJMKsASLPClpn3Snc2VA_yRswl_bf_hklFhOmojIKLrJrHyTppbvtTXO-LIiId67tN-cuB_vfN4yPIlWCN=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2014/09/mining-bitcoin-with-pencil-and-paper.html'>Mining Bitcoin with pencil and paper: 0.67 hashes per day</a></div> </div> <div style='clear: both;'></div> </li> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2012/02/apple-didnt-revolutionize-power.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_uY8pT7miQq_GGJ7q0Wn1fZsYpMAVA1T2T-1W-mNq0De3pc0wKJH9vVFS-fCe9Zf7Fn8nh5KYLmiEFvay7V08EcgSX64VY1EyM8Kank4ncgN4g=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2012/02/apple-didnt-revolutionize-power.html'>Apple didn't revolutionize power supplies; new transistors did</a></div> </div> <div style='clear: both;'></div> </li> </ul> <div class='clear'></div> </div> </div><div class='widget BlogSearch' data-version='1' id='BlogSearch1'> <h2 class='title'>Search This Blog</h2> <div class='widget-content'> <div id='BlogSearch1_form'> <form action='http://www.righto.com/search' class='gsc-search-box' target='_top'> <table cellpadding='0' cellspacing='0' class='gsc-search-box'> <tbody> <tr> <td class='gsc-input'> <input autocomplete='off' class='gsc-input' name='q' size='10' title='search' type='text' value=''/> </td> <td class='gsc-search-button'> <input class='gsc-search-button' title='search' type='submit' value='Search'/> </td> </tr> </tbody> </table> </form> </div> </div> <div class='clear'></div> </div><div class='widget Label' data-version='1' id='Label1'> <h2>Labels</h2> <div class='widget-content cloud-label-widget-content'> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/386'>386</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/6502'>6502</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/8008'>8008</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/8085'>8085</a> </span> <span class='label-size label-size-4'> <a dir='ltr' href='http://www.righto.com/search/label/8086'>8086</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/8087'>8087</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/8088'>8088</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/aerospace'>aerospace</a> </span> <span class='label-size label-size-3'> <span dir='ltr'>alto</span> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/analog'>analog</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/Apollo'>Apollo</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/apple'>apple</a> </span> <span class='label-size label-size-4'> <a dir='ltr' href='http://www.righto.com/search/label/arc'>arc</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/arduino'>arduino</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/arm'>arm</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/beaglebone'>beaglebone</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/bitcoin'>bitcoin</a> </span> <span class='label-size label-size-1'> <a dir='ltr' href='http://www.righto.com/search/label/c%23'>c#</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/cadc'>cadc</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/calculator'>calculator</a> </span> <span class='label-size label-size-4'> <a dir='ltr' href='http://www.righto.com/search/label/chips'>chips</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/css'>css</a> </span> <span class='label-size label-size-1'> <a dir='ltr' href='http://www.righto.com/search/label/datapoint'>datapoint</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/dx7'>dx7</a> </span> <span class='label-size label-size-5'> <a dir='ltr' href='http://www.righto.com/search/label/electronics'>electronics</a> </span> <span class='label-size label-size-1'> <a dir='ltr' href='http://www.righto.com/search/label/f%23'>f#</a> </span> <span class='label-size label-size-1'> <a dir='ltr' href='http://www.righto.com/search/label/fairchild'>fairchild</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/fpga'>fpga</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/fractals'>fractals</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/genome'>genome</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/globus'>globus</a> </span> <span class='label-size label-size-1'> <a dir='ltr' href='http://www.righto.com/search/label/haskell'>haskell</a> </span> <span class='label-size label-size-1'> <a dir='ltr' href='http://www.righto.com/search/label/HP'>HP</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/html5'>html5</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/ibm'>ibm</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/ibm1401'>ibm1401</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/ibm360'>ibm360</a> </span> <span class='label-size label-size-4'> <a dir='ltr' href='http://www.righto.com/search/label/intel'>intel</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/ipv6'>ipv6</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/ir'>ir</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/java'>java</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/javascript'>javascript</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/math'>math</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/microcode'>microcode</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/oscilloscope'>oscilloscope</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/Pentium'>Pentium</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/photo'>photo</a> </span> <span class='label-size label-size-4'> <a dir='ltr' href='http://www.righto.com/search/label/power%20supply'>power supply</a> </span> <span class='label-size label-size-4'> <a dir='ltr' href='http://www.righto.com/search/label/random'>random</a> </span> <span class='label-size label-size-5'> <a dir='ltr' href='http://www.righto.com/search/label/reverse-engineering'>reverse-engineering</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/sheevaplug'>sheevaplug</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/snark'>snark</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/space'>space</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/spanish'>spanish</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/synth'>synth</a> </span> <span class='label-size label-size-4'> <a dir='ltr' href='http://www.righto.com/search/label/teardown'>teardown</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/theory'>theory</a> </span> <span class='label-size label-size-1'> <a dir='ltr' href='http://www.righto.com/search/label/unicode'>unicode</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/Z-80'>Z-80</a> </span> <div class='clear'></div> </div> </div><div class='widget BlogArchive' data-version='1' id='BlogArchive1'> <h2>Blog Archive</h2> <div class='widget-content'> <div id='ArchiveList'> <div id='BlogArchive1_ArchiveList'> <ul class='hierarchy'> <li class='archivedate expanded'> <a class='toggle' href='javascript:void(0)'> <span class='zippy toggle-open'> ▼  </span> </a> <a class='post-count-link' href='http://www.righto.com/2025/'> 2025 </a> <span class='post-count' dir='ltr'>(8)</span> <ul class='hierarchy'> <li class='archivedate expanded'> <a class='toggle' href='javascript:void(0)'> <span class='zippy toggle-open'> ▼  </span> </a> <a class='post-count-link' href='http://www.righto.com/2025/03/'> March </a> <span class='post-count' dir='ltr'>(3)</span> <ul class='posts'> <li><a href='http://www.righto.com/2025/03/pentium-microcde-rom-circuitry.html'>Notes on the Pentium's microcode circuitry</a></li> <li><a href='http://www.righto.com/2025/03/mother-of-all-demos-usb-keyset-interface.html'>A USB interface to the "Mother of All Demos" keyset</a></li> <li><a href='http://www.righto.com/2025/03/pentium-multiplier-adder-reverse-engineered.html'>The Pentium contains a complicated circuit to mult...</a></li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2025/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2025/01/'> January </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/'> 2024 </a> <span class='post-count' dir='ltr'>(21)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/12/'> December </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/11/'> November </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/10/'> October </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/09/'> September </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/08/'> August </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/07/'> July </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/06/'> June </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/02/'> February </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/01/'> January </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/'> 2023 </a> <span class='post-count' dir='ltr'>(35)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/12/'> December </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/11/'> November </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/10/'> October </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/09/'> September </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/08/'> August </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/07/'> July </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/04/'> April </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/03/'> March </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/02/'> February </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/01/'> January </a> <span class='post-count' dir='ltr'>(8)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/'> 2022 </a> <span class='post-count' dir='ltr'>(18)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/11/'> November </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/07/'> July </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/06/'> June </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/04/'> April </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/02/'> February </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/01/'> January </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/'> 2021 </a> <span class='post-count' dir='ltr'>(26)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/12/'> December </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/11/'> November </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/09/'> September </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/07/'> July </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/06/'> June </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/04/'> April </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/03/'> March </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/02/'> February </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/01/'> January </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/'> 2020 </a> <span class='post-count' dir='ltr'>(33)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/11/'> November </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/10/'> October </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/09/'> September </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/08/'> August </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/07/'> July </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/06/'> June </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/05/'> May </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/04/'> April </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/03/'> March </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/'> 2019 </a> <span class='post-count' dir='ltr'>(18)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/11/'> November </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/10/'> October </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/09/'> September </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/07/'> July </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/04/'> April </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/01/'> January </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/'> 2018 </a> <span class='post-count' dir='ltr'>(17)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/12/'> December </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/09/'> September </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/06/'> June </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/03/'> March </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/01/'> January </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/'> 2017 </a> <span class='post-count' dir='ltr'>(21)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/12/'> December </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/11/'> November </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/10/'> October </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/07/'> July </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/06/'> June </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/04/'> April </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/'> 2016 </a> <span class='post-count' dir='ltr'>(34)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/10/'> October </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/09/'> September </a> <span class='post-count' dir='ltr'>(8)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/08/'> August </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/07/'> July </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/06/'> June </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/03/'> March </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/02/'> February </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/01/'> January </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/'> 2015 </a> <span class='post-count' dir='ltr'>(12)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/11/'> November </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/10/'> October </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/05/'> May </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2014/'> 2014 </a> <span class='post-count' dir='ltr'>(13)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2014/12/'> December </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2014/10/'> October </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2014/09/'> September </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2014/05/'> May </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2014/03/'> March </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2014/02/'> February </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/'> 2013 </a> <span class='post-count' dir='ltr'>(24)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/11/'> November </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/09/'> September </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/08/'> August </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/07/'> July </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/06/'> June </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/02/'> February </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/01/'> January </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2012/'> 2012 </a> <span class='post-count' dir='ltr'>(10)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2012/12/'> December </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2012/11/'> November </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2012/10/'> October </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2012/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2012/03/'> March </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2012/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2011/'> 2011 </a> <span class='post-count' dir='ltr'>(11)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2011/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2011/07/'> July </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2011/05/'> May </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2011/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2011/03/'> March </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2011/02/'> February </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/'> 2010 </a> <span class='post-count' dir='ltr'>(22)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/11/'> November </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/10/'> October </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/06/'> June </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/05/'> May </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/04/'> April </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/03/'> March </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/01/'> January </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/'> 2009 </a> <span class='post-count' dir='ltr'>(22)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/11/'> November </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/09/'> September </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/08/'> August </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/07/'> July </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/06/'> June </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/03/'> March </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/02/'> February </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2008/'> 2008 </a> <span class='post-count' dir='ltr'>(27)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2008/07/'> July </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2008/06/'> June </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2008/05/'> May </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2008/04/'> April </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2008/03/'> March </a> <span class='post-count' dir='ltr'>(10)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2008/02/'> February </a> <span class='post-count' dir='ltr'>(6)</span> </li> </ul> </li> </ul> </div> </div> <div class='clear'></div> </div> </div></div> </aside> </div> </div> </div> <div style='clear: both'></div> <!-- columns --> </div> <!-- main --> </div> </div> <div class='main-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <footer> <div class='footer-outer'> <div class='footer-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left footer-fauxborder-left'> <div class='fauxborder-right footer-fauxborder-right'></div> <div class='region-inner footer-inner'> <div class='foot no-items section' id='footer-1'></div> <table border='0' cellpadding='0' cellspacing='0' class='section-columns columns-2'> <tbody> <tr> <td class='first columns-cell'> <div class='foot no-items section' id='footer-2-1'></div> </td> <td class='columns-cell'> <div class='foot no-items section' id='footer-2-2'></div> </td> </tr> </tbody> </table> <!-- outside of the include in order to lock Attribution widget --> <div class='foot section' id='footer-3'><div class='widget Attribution' data-version='1' id='Attribution1'> <div class='widget-content' style='text-align: center;'> Powered by <a href='https://www.blogger.com' target='_blank'>Blogger</a>. </div> <div class='clear'></div> </div></div> </div> </div> <div class='footer-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </footer> <!-- content --> </div> </div> <div class='content-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </div> <script type='text/javascript'> window.setTimeout(function() { document.body.className = document.body.className.replace('loading', ''); }, 10); </script> <script type="text/javascript" src="https://www.blogger.com/static/v1/widgets/1455187647-widgets.js"></script> <script type='text/javascript'> window['__wavt'] = 'AOuZoY56LYyC-hbzsCKsJRjch4ik6oIweg:1743442311180';_WidgetManager._Init('//www.blogger.com/rearrange?blogID\x3d6264947694886887540','//www.righto.com/search/label/alto','6264947694886887540'); _WidgetManager._SetDataContext([{'name': 'blog', 'data': {'blogId': '6264947694886887540', 'title': 'Ken Shirriff\x27s blog', 'url': 'http://www.righto.com/search/label/alto', 'canonicalUrl': 'http://www.righto.com/search/label/alto', 'homepageUrl': 'http://www.righto.com/', 'searchUrl': 'http://www.righto.com/search', 'canonicalHomepageUrl': 'http://www.righto.com/', 'blogspotFaviconUrl': 'http://www.righto.com/favicon.ico', 'bloggerUrl': 'https://www.blogger.com', 'hasCustomDomain': true, 'httpsEnabled': false, 'enabledCommentProfileImages': true, 'gPlusViewType': 'FILTERED_POSTMOD', 'adultContent': false, 'analyticsAccountNumber': 'UA-3782444-1', 'encoding': 'UTF-8', 'locale': 'en', 'localeUnderscoreDelimited': 'en', 'languageDirection': 'ltr', 'isPrivate': false, 'isMobile': false, 'isMobileRequest': false, 'mobileClass': '', 'isPrivateBlog': false, 'isDynamicViewsAvailable': true, 'feedLinks': '\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Ken Shirriff\x26#39;s blog - Atom\x22 href\x3d\x22http://www.righto.com/feeds/posts/default\x22 /\x3e\n\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/rss+xml\x22 title\x3d\x22Ken Shirriff\x26#39;s blog - RSS\x22 href\x3d\x22http://www.righto.com/feeds/posts/default?alt\x3drss\x22 /\x3e\n\x3clink rel\x3d\x22service.post\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Ken Shirriff\x26#39;s blog - Atom\x22 href\x3d\x22https://www.blogger.com/feeds/6264947694886887540/posts/default\x22 /\x3e\n', 'meTag': '\x3clink rel\x3d\x22me\x22 href\x3d\x22https://www.blogger.com/profile/08097301407311055124\x22 /\x3e\n', 'adsenseHostId': 'ca-host-pub-1556223355139109', 'adsenseHasAds': false, 'adsenseAutoAds': false, 'boqCommentIframeForm': true, 'loginRedirectParam': '', 'view': '', 'dynamicViewsCommentsSrc': '//www.blogblog.com/dynamicviews/4224c15c4e7c9321/js/comments.js', 'dynamicViewsScriptSrc': '//www.blogblog.com/dynamicviews/6c9901d4a96a9be5', 'plusOneApiSrc': 'https://apis.google.com/js/platform.js', 'disableGComments': true, 'interstitialAccepted': false, 'sharing': {'platforms': [{'name': 'Get link', 'key': 'link', 'shareMessage': 'Get link', 'target': ''}, {'name': 'Facebook', 'key': 'facebook', 'shareMessage': 'Share to Facebook', 'target': 'facebook'}, {'name': 'BlogThis!', 'key': 'blogThis', 'shareMessage': 'BlogThis!', 'target': 'blog'}, {'name': 'X', 'key': 'twitter', 'shareMessage': 'Share to X', 'target': 'twitter'}, {'name': 'Pinterest', 'key': 'pinterest', 'shareMessage': 'Share to Pinterest', 'target': 'pinterest'}, {'name': 'Email', 'key': 'email', 'shareMessage': 'Email', 'target': 'email'}], 'disableGooglePlus': true, 'googlePlusShareButtonWidth': 0, 'googlePlusBootstrap': '\x3cscript type\x3d\x22text/javascript\x22\x3ewindow.___gcfg \x3d {\x27lang\x27: \x27en\x27};\x3c/script\x3e'}, 'hasCustomJumpLinkMessage': false, 'jumpLinkMessage': 'Read more', 'pageType': 'index', 'searchLabel': 'alto', 'pageName': 'alto', 'pageTitle': 'Ken Shirriff\x27s blog: alto'}}, {'name': 'features', 'data': {}}, {'name': 'messages', 'data': {'edit': 'Edit', 'linkCopiedToClipboard': 'Link copied to clipboard!', 'ok': 'Ok', 'postLink': 'Post Link'}}, {'name': 'template', 'data': {'name': 'custom', 'localizedName': 'Custom', 'isResponsive': false, 'isAlternateRendering': false, 'isCustom': true}}, {'name': 'view', 'data': {'classic': {'name': 'classic', 'url': '?view\x3dclassic'}, 'flipcard': {'name': 'flipcard', 'url': '?view\x3dflipcard'}, 'magazine': {'name': 'magazine', 'url': '?view\x3dmagazine'}, 'mosaic': {'name': 'mosaic', 'url': '?view\x3dmosaic'}, 'sidebar': {'name': 'sidebar', 'url': '?view\x3dsidebar'}, 'snapshot': {'name': 'snapshot', 'url': '?view\x3dsnapshot'}, 'timeslide': {'name': 'timeslide', 'url': '?view\x3dtimeslide'}, 'isMobile': false, 'title': 'Ken Shirriff\x27s blog', 'description': 'Computer history, restoring vintage computers, IC reverse engineering, and whatever', 'url': 'http://www.righto.com/search/label/alto', 'type': 'feed', 'isSingleItem': false, 'isMultipleItems': true, 'isError': false, 'isPage': false, 'isPost': false, 'isHomepage': false, 'isArchive': false, 'isSearch': true, 'isLabelSearch': true, 'search': {'label': 'alto', 'resultsMessage': 'Showing posts with the label alto', 'resultsMessageHtml': 'Showing posts with the label \x3cspan class\x3d\x27search-label\x27\x3ealto\x3c/span\x3e'}}}]); _WidgetManager._RegisterWidget('_HeaderView', new _WidgetInfo('Header1', 'header', document.getElementById('Header1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogView', new _WidgetInfo('Blog1', 'main', document.getElementById('Blog1'), {'cmtInteractionsEnabled': false, 'navMessage': 'Showing posts with label \x3cb\x3ealto\x3c/b\x3e. \x3ca href\x3d\x22http://www.righto.com/\x22\x3eShow all posts\x3c/a\x3e'}, 'displayModeFull')); _WidgetManager._RegisterWidget('_HTMLView', new _WidgetInfo('HTML2', 'sidebar-right-1', document.getElementById('HTML2'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_HTMLView', new _WidgetInfo('HTML3', 'sidebar-right-1', document.getElementById('HTML3'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_PopularPostsView', new _WidgetInfo('PopularPosts1', 'sidebar-right-1', document.getElementById('PopularPosts1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogSearchView', new _WidgetInfo('BlogSearch1', 'sidebar-right-1', document.getElementById('BlogSearch1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_LabelView', new _WidgetInfo('Label1', 'sidebar-right-1', document.getElementById('Label1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogArchiveView', new _WidgetInfo('BlogArchive1', 'sidebar-right-1', document.getElementById('BlogArchive1'), {'languageDirection': 'ltr', 'loadingMessage': 'Loading\x26hellip;'}, 'displayModeFull')); _WidgetManager._RegisterWidget('_AttributionView', new _WidgetInfo('Attribution1', 'footer-3', document.getElementById('Attribution1'), {}, 'displayModeFull')); </script> </body> </html>