CINXE.COM

Joshua Tauberer’s Homepage

<!DOCTYPE html> <html> <head> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Joshua Tauberer&rsquo;s Homepage</title> <meta name="description" content="Joshua Tauberer is a civic technologist in Washington, DC, USA."> <meta property="og:image" content="https://joshdata.me/static/img/me.jpeg" /> <meta name="twitter:creator" content="@JoshData" /> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap-theme.min.css"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"> <link rel="stylesheet" href="static/css/main.css"> </head> <body> <div class="container"> <div id="myname" class="row"> <div class="col-sm-5 col-md-4"> <div id="img-wrapper"> <img src="static/img/me.jpeg" class="img-responsive"/> </div> </div> <div class="col-sm-6"> <div> <h1 style="margin-top: 0">Joshua Tauberer<small>, &nbsp;Ph.D.</small></h1> <p id="links"> <i class="fa fa-envelope-o"></i> <script> var email_addr = "hsoj".split("").reverse().join("") + String.fromCharCode(2*0x20) + "atadhsoj".split("").reverse().join("") + "." + "em".split("").reverse().join(""); document.write("\x3ca class='first' href='mailto:" + email_addr + "'\x3e" + email_addr + "\x3c/a\x3e"); </script><noscript>email address protected from spambots; use a JavaScript-enabled browser to see it</noscript> <br><i class="fa fa-user-o"></i> <a rel="me" href="https://mastodon.joshdata.me/@josh">@josh@joshdata.me</a> <span style="font-size: 90%; color: #777">(Mastodon)</span> <!--<br><i class="fa fa-twitter"></i> <a href="http://twitter.com/joshdata">twitter.com/JoshData</a>--> <br><i class="fa fa-github"></i> <a href="https://github.com/joshdata/">github.com/JoshData</a> <br><i class="fa fa-list"></i> <a href="cv.html">resume</a> </p> <p>I am a software engineering manager and civic hacker living in Washington, DC with experience in scientific computing and data analysis, civic and government technology and advocacy, and cybersecurity compliance. I am best known for creating <a href="https://www.govtrack.us">GovTrack.us</a>, the widely used educational website about the U.S. Congress. I am currently the Head of Product Development at <a href="https://www.larsa4d.com">LARSA</a> and previously held numerous consulting and co-founder roles related to information technology innovation in government.</p> </div> </div> </div> </div> <div class="mondrianish"></div> <div id="about-me"> <div class="container"> <table> <tr valign="top"> <td style="padding: 2px 2em 0 0; width: 20%;"><a href="http://www.larsa4d.com"><img src="static/img/larsa.jpg" class="img-responsive" title="LARSA, Inc."/></a></td> <td style="padding-bottom: 1em;"> <h3><a href="http://www.larsa4d.com">LARSA, Inc.</a> <span>Head of Product Development</span></h3> <p>Multinational construction companies rely on desktop software developed by LARSA, Inc. to design billion-dollar bridges and other complex structures, from overpasses in the District of Columbia to world-renowned cable-supported bridges throughout the world. As Head of Product Development, I manage the development of LARSA’s legacy and emerging products and a small team of software engineers.</p> </td> </tr> <tr valign="top"> <td style="padding: 2px 2em 0 0; width: 20%;"><a href="https://www.govtrack.us"><img src="static/img/govtrack.png" class="img-responsive" title="GovTrack.us" style="border: 1px solid #555;" /></a></td> <td> <h3><a href="https://www.govtrack.us">GovTrack.us</a> <span>Founder</span></h3> <p>In 2003 I founded what would become one of the world’s most visited free government information websites, www.GovTrack.us. The website helps 10 million Americans annually &mdash; students, educators, politically active Americans, lobbyists, and other legislative professionals &mdash; track the daily activities of the United States Congress in an easily consumable form, catalyzed the world-wide “open government data” movement in the mid 2000’s, and inspired Congress’s efforts in the 2010’s to create its first official “bulk data download” of legislative information.</p> </td> </tr> </table> </div> <div class="mondrianish"></div> <div class="container"> <p>Some of my side projects on the web:</p> <div class="row"> <div class="col-sm-6"> <table> <tr valign="top"> <td style="padding: 2px 2em 2em 0; width: 20%;"><a href="https://mailinabox.email"><img src="static/img/mailinabox.png" class="img-responsive" title="Mail-in-a-Box"/></a></td> <td style="padding-bottom: 1em;"> <h3><a href="https://mailinabox.email">Mail-in-a-Box</a></h3> <p>Mail-in-a-Box is an open source project to make deploying a good mail server without system administration experience, promoting decentralization on the web. The project has an active community of users on the discussion forum and our Slack channel.</p> </td> </tr> </table> </div> <div class="col-sm-6"> <table> <tr valign="top"> <td style="padding: 2px 2em 2em 0; width: 20%;"><a href="iceberger.html"><img src="static/img/iceberger.png" class="img-responsive" title="Iceberger" style="border: 1px solid #555;" /></a></td> <td style="padding-bottom: 1em;"> <h3><a href="iceberger.html">Iceberger</a></h3> <p>Icebergs are less dense than water, so they always float with about 10% of their mass above the water. But which way up? Draw an iceberg and see how it floats. This little onepager went a little viral in early 2021.</p> </td> </tr> </table> </div> </div> <p>Also:</p> <p> <a href="https://github.com/unitedstates/congress-legislators">congress-legislators</a> | <a href="https://github.com/unitedstates/congress">congress</a> | <a href="https://github.com/unitedstates/legisworks-historical-statutes">legisworks-historical-statutes</a> </p> <p> <a href="https://github.com/JoshData/python-email-validator">python-email-validator</a> | <a href="https://github.com/JoshData/fast_diff_match_patch">fast_diff_match_patch</a> | <a href="https://github.com/unitedstates/rtyaml">rtyaml</a> | <a href="https://github.com/JoshData/convert-outlook-msg-file">convert-outlook-msg-file</a> </p> <p> <a href="https://everycrsreport.com">EveryCRSReport.com</a> | <a href="https://uslaw.link">uslaw.link</a> | <a href="https://ツ.life">ツ.life</a> | <a href="https://joshdata.github.io/infinite-tree">Infinite Tree</a> </p> </div> <!--/container--> <div class="mondrianish"></div> <div class="container"> <div class="row"> <div class="col-sm-3"> <p><b>New Posts</b></p> <p><a href="https://joshuatauberer.medium.com/we-went-solar-and-here-are-the-real-numbers-7a7f28d51897">We went solar and here are the real numbers</a> (2021)</p> <p><a href="https://joshuatauberer.medium.com/what-three-weeks-in-japan-taught-me-about-public-transit-signage-77bfc2d6e824">What three weeks in Japan taught me about public transit signage</a> (2020)</p> <p><a href="https://joshuatauberer.medium.com/a-personal-taxonomy-of-jewishness-9b6dbc3797d7">A personal taxonomy of jewishness</a> (2020)</p> </div> <div class="col-sm-4"> <p><b>Tech/Data</b></p> <p><a href="https://joshuatauberer.medium.com/write-joyous-git-commit-messages-2f98891114c4">Write joyous git commit messages</a> (2019)</p> <p><a href="https://medium.com/@joshuatauberer/how-that-map-you-saw-on-538-under-represents-minorities-by-half-and-other-reasons-to-consider-a-4a98f89cbbb1#.qwsr3tdjw">How that map you saw on FiveThirtyEight silences minorities, and other reasons to consider a cartogram.</a> (2016)</p> <p style="padding: 1em 2em"><a href="https://medium.com/@joshuatauberer/how-that-map-you-saw-on-538-under-represents-minorities-by-half-and-other-reasons-to-consider-a-4a98f89cbbb1#.qwsr3tdjw"><img src="static/img/cartograms.png" class="img-responsive"></a> </div> <div class="col-sm-5"> <p><b>Civic Tech</b></p> <p><a href="https://arstechnica.com/tech-policy/2018/11/how-i-changed-the-law-with-a-github-pull-request/">How I changed the law with a GitHub pull request</a><br> I made the first ever change to a law via pull request. (2018)</p> <p><a href="https://medium.com/@joshuatauberer/so-you-want-to-reform-democracy-7f3b1ef10597#.tsl9l6umh">So you want to reform democracy?</a><br> Hello. You probably just wrote me an email about fixing democracy. (2015)</p> <p><a href="https://opengovdata.io">Open Government Data: The Book</a> (2012/2014)</p> <p><a href="https://hackathon.guide">Hackathon.guide</a><br> A logistical guide to running a successful technology hackathon. (2014)</p> </div> </div> <p><i class="fa fa-file-text"></i> <a href="https://medium.com/@joshuatauberer">other blog posts</a> (<a href="blog">archived posts</a>)</p> <div class="row"> <div class="col-sm-6"> <div class="row"> <div class="col-xs-2"> <a href="rupert.html"><img src="static/img/rupert.jpeg" title="Rupert the Turtle" class="img-responsive"/></a> </div> <div class="col-xs-10"> <p>This is my pet turtle, <a href="rupert.html">Rupert</a>, who has his own homepage and occassionally <a href="https://twitter.com/joshdataturtle">tweets</a>.</p> </div> </div> </div> <!-- <div class="col-sm-6"> <p>PGP key: <br><a href="https://keybase.io/joshdata">keybase.io/joshdata</a> / <a href="https://keybase.io/joshdata/key.asc">key.asc</a> <br><small>5F4C 0E73 13CC D744 693B 2AEA <b>B920 41F4 C10B DD81</b></small></p> </div> --> </div> </div> </div> <div class="mondrianish"></div> <p class="quote">&ldquo;If you already know what recursion is, just remember the answer. Otherwise, find someone who is standing closer to Douglas Hofstadter than you are; then ask him or her what recursion is.&rdquo; -- Andrew Plotkin</p> <script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n" crossorigin="anonymous"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js"></script> <script> // mondrianish // https://github.com/GovReady/mondrianish/pull/3/files function random_element(array) { return array[Math.floor(Math.random() * array.length)]; } function generate_grid(canvas_size, density) { /* Generate a Piet Mondrian-style image composed of rectangles of various colors. This function generates the image in grid form and returns the lines and rectangles that make up the image. The parameters are: canvas_size: An array [width, height], where width and height are integers, generally small like [20, 20]. density: How many rectangles should the grid be divided into? The default is 0.5 and raising or lowering it a bit will create more or fewer divisions. The return value is an object { lines: ..., rectagles: ...}, each an array. Each line and rectangle is of the form [[startx, starty], [endx, endy]]. The coordinates are integers in the range of (0, 0) to (width-1, height-1). The key feature of these images is that they are made up of horizontal and vertical line segments that terminate at the canvas edges or at other line segments, leaving rectangular open spaces in the middle to be filled in with various colors. Other programs that create Mondrian-style images tend to recursively break up the canvas into pieces, as if it were a fractal, but a general Mondrian-style image is not really structured this way. So the technique here instead is to draw lines first, one after another, only adding valid lines, and then afterward to see how those lines break up the canvas into rectangles. */ if (canvas_size[0] < 3 || canvas_size[1] < 3) throw "Canvas size must be at least 3-by-3."; if (typeof density === "undefined") density = .5; // Start constructing line segments iteratively. var lines = []; for (var i = 0; i < (canvas_size[0]*canvas_size[1])**density; i++) { // Shall we draw a vertical (0) or horizontal (1) line? Choose randomly. var direction = random_element([0, 1]) // Pick a line segment perpendicular to our chosen direction // to be the left/top edge of the new segment, or start at the // left/top edge of the canvas (represented by null). var possible_starts = lines.filter(function(line) { return line.direction != direction }); var lefttop = random_element([null].concat(possible_starts)); // Which lines can the new segment validly end at? Any // other perpendicular line to the right of or below the // start and that has some overlap in coordinates. Choose // randomly. function intervals_overalp(a1, a2, b1, b2) { return (a1 <= b1 && b1 <= a2) || (a1 <= b2 && b2 <= a2) || (b1 <= a1 && a1 <= b2) || (b1 <= a2 && a2 <= b2); } var possible_ends = lines.filter(function(line) { return line.direction != direction && (lefttop === null || (line.x > lefttop.x && intervals_overalp(lefttop.y1, lefttop.y2, line.y1, line.y2))); }); var rightbottom = random_element([null].concat(possible_ends)); // What coorindate should our new line be at? It can be at // any value within the canvas_size's dimensions, except on the // edges... var coordrange = [1, canvas_size[direction]-1]; // And it can't be to the left or right of either the start or // end segment or exactly on their ends... if (lefttop !== null) coordrange = [Math.max(coordrange[0], lefttop.y1+1), Math.min(coordrange[1], lefttop.y2-1)]; if (rightbottom !== null) coordrange = [Math.max(coordrange[0], rightbottom.y1+1), Math.min(coordrange[1], rightbottom.y2-1)]; // Turn the range into a sequence of integers of possible good locations // that we'll randomly draw from. if (coordrange[1] < coordrange[0]) continue; var possible_coordinates = new Array(coordrange[1]-coordrange[0]+1).fill(0).map(function(x,i) { return coordrange[0] + i; }); // And there may not be a segment there already or in a neighboring // coordinate, because then there's no area between them to fill. lines.forEach(function(line) { if ( line.direction == direction && (rightbottom === null ? true : line.y1 <= rightbottom.x) && (lefttop === null ? true : line.y2 >= lefttop.x)) for (var x = line.x-1; x <= line.x+1; x++) { // Remove x. var idx = possible_coordinates.indexOf(x); if (idx != -1) possible_coordinates.splice(idx, 1); } }); // Can't put a line here? if (possible_coordinates.length == 0) continue; // Choose a random location. var coordinate = random_element(possible_coordinates); // Add the line. lines.push({ direction: direction, x: coordinate, y1: lefttop === null ? 0 : lefttop.x, y2: rightbottom === null ? (canvas_size[1-direction]-1) : rightbottom.x }); } // Determine the rectangles from the lines. Start with a // single rectangle for the whole canvas_size and divide as // needed every time a line intersects a rectangle. var rectangles = [[[0,0], [canvas_size[0]-1, canvas_size[1]-1]]] lines.forEach(function(line) { rectangles.forEach(function(rect) { // Does this rectangle need to be divided? if (rect.killed) return; if (line.direction == 0 && rect[0][0] < line.x && line.x < rect[1][0] && line.y1 <= rect[0][1] && line.y2 >= rect[1][1]) { rectangles.push([[rect[0][0], rect[0][1]], [line.x, rect[1][1]]]); rectangles.push([[line.x, rect[0][1]], [rect[1][0], rect[1][1]]]); rect.killed = true; } else if (line.direction == 1 && rect[0][1] < line.x && line.x < rect[1][1] && line.y1 <= rect[0][0] && line.y2 >= rect[1][0]) { rectangles.push([[rect[0][0], rect[0][1]], [rect[1][0], line.x]]); rectangles.push([[rect[0][0], line.x], [rect[1][0], rect[1][1]]]); rect.killed = true; } }); }); rectangles = rectangles.filter(function(rect) { return !rect.killed; }); // Re-bake the lines to be in start-end coordinate form. lines = lines.map(function(line) { return (line.direction == 0 ? [[line.x, line.y1], [line.x, line.y2]] : [[line.y1, line.x], [line.y2, line.x]]); }); return { lines: lines, rectangles: rectangles }; } </script> <style> .mondrianish .line { border: 4px solid white; } </style> <script> var colors = ["#EEE8F0", "#FCAA67", "#7DB7C0", "#932b25", "#498B57", "#333333", "#cf1c8a"]; $('.mondrianish').each(function() { var container = $(this); container.css({ width: "100%", height: "15vh", position: "relative", margin: "2em 0" }); var grid_width = 12; var grid_height = parseInt(15*$(window).height()/$(window).width()); var ngroups = 3; var mondrian = generate_grid([grid_width+1, grid_height+1]); mondrian.rectangles.forEach(function(rect) { var node = $("<div class='cell'></div>"); node.css({ position: 'absolute', left: (rect[0][0]/grid_width*100)+"%", top: (rect[0][1]/grid_height*100)+"%", width: ((rect[1][0]-rect[0][0])/grid_width*100)+"%", height: ((rect[1][1]-rect[0][1])/grid_height*100)+"%", backgroundColor: random_element(colors) }); node.addClass("group" + parseInt(Math.random()*ngroups)); container.append(node); }); mondrian.lines.forEach(function(line) { var node = $("<div class='line'></div>"); node.css({ position: 'absolute', left: (line[0][0]/grid_width*100)+"%", top: (line[0][1]/grid_height*100)+"%", width: ((line[1][0]-line[0][0])/grid_width*100)+"%", height: ((line[1][1]-line[0][1])/grid_height*100)+"%" }); container.append(node); }); }); </script> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10