diff options
| author | Owen Jacobson <owen.jacobson@grimoire.ca> | 2015-12-09 20:40:42 -0500 |
|---|---|---|
| committer | Owen Jacobson <owen.jacobson@grimoire.ca> | 2015-12-09 20:40:42 -0500 |
| commit | f82d259e7bda843fb63ac1a0f6ff1d6bfb187099 (patch) | |
| tree | 502ebf27ea72cf8c6025b880bfdb35db00ce8b92 /.html | |
| parent | 75a219a061b60bb32948b8a2b71c8ccf1dc19a62 (diff) | |
Remove HTML from the project. (We're no longer using Dokku.)
Diffstat (limited to '.html')
111 files changed, 0 insertions, 15201 deletions
diff --git a/.html/12factor/3-config.html b/.html/12factor/3-config.html deleted file mode 100644 index a7f58cf..0000000 --- a/.html/12factor/3-config.html +++ /dev/null @@ -1,106 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Factor 3: Config - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">12factor</a> - - </li> - - <li class="crumb-2 last"> - - 3-config - - </li> - - </ol> - - - - <div id="article"> - <h1 id="factor-3-config">Factor 3: Config</h1> -<p><a href="http://www.12factor.net/config">This section</a> advises using environment -variables for everything.</p> -<blockquote> -<p><a href="https://twitter.com/derspiny">Owen J</a>: I think I disagree with -12factor's conclusions on config even though I agree with the premises -and rationale in general</p> -<p><a href="https://twitter.com/derspiny">Owen J</a>: environment variables -are neither exceptionally portable, exceptionally standard, nor -exceptionally easy to manage</p> -<p><a href="https://twitter.com/derspiny">Owen J</a>: and therefore should not be -the exceptional configuration mechanism :)</p> -<p><a href="https://twitter.com/wlonk">Kit L</a>: that's exactly the critique i have</p> -</blockquote> -<p>Frustratingly, the config section doesn't provide any guidance on sensible -ways to <em>manage</em> environment variables. In any real-world deployment, they're -going to have to be stored somewhere; where's appropriate? <code>.bash_profile</code>? -<code>httpd.con</code> as <code>SetEnv</code> directives? Per-release <code>rc</code> files? <code>/etc/init.d</code>?</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/12factor/3-config.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/12factor/3-config.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/12factor/7-port-binding.html b/.html/12factor/7-port-binding.html deleted file mode 100644 index 738e1b0..0000000 --- a/.html/12factor/7-port-binding.html +++ /dev/null @@ -1,124 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Factor 7: Port Binding - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">12factor</a> - - </li> - - <li class="crumb-2 last"> - - 7-port-binding - - </li> - - </ol> - - - - <div id="article"> - <h1 id="factor-7-port-binding">Factor 7: Port Binding</h1> -<p><a href="http://www.12factor.net/port-binding">This</a> is the exact point where the -Heroku-specific features of the approach overwhelm the general features.</p> -<p>Factor 7 is over-specific:</p> -<ul> -<li> -<p>It presupposes the existence of a front-end routing layer, without providing - any insight into how to deploy, configure, provision, or manage one.</p> -</li> -<li> -<p>It demands HTTP (by name) rather than a more flexible “any well-standardized - protocol,” without explaining why. (Web apps can have non-HTTP internal - components.)</p> -</li> -<li> -<p>It dismisses the value of “pre-existing” container ecosystems that don't - work the way Heroku does. Have a giant, well-managed - <a href="http://glassfish.org">Glassfish</a> cluster that you deploy components to? TOO - BAD, not Heroku-like enough for these guys even though many aspects run - along similar philosophical lines.</p> -</li> -<li> -<p>It dismisses the value of unix-as-a-container. Unix domain sockets with - controlled permissions? Psh, let's go through the network stack instead. - SysV IPC? (Yeah, I know.) Network. Pipes? Network. There's an implicit - exception for “intra-process” communication, but it's never really - identified or reasoned about.</p> -</li> -<li> -<p>Have you <em>seen</em> the kinds of process control interfaces developers invent, - when left to their own devices? Signals and PID files are well-established - conventions, and smart, competent people still fuck those up all the time. - Command-line arguments are another frequent case of NIH stupidity. Do you - really want every app to have its own startup API?</p> -</li> -</ul> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/12factor/7-port-binding.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/12factor/7-port-binding.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/12factor/_list.html b/.html/12factor/_list.html deleted file mode 100644 index 3980ee1..0000000 --- a/.html/12factor/_list.html +++ /dev/null @@ -1,90 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /12factor - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">12factor</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /12factor</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="3-config">Factor 3: Config</a></li> - - <li><a href="7-port-binding">Factor 7: Port Binding</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/12factor">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/12factor/index.html b/.html/12factor/index.html deleted file mode 100644 index cb5bcc9..0000000 --- a/.html/12factor/index.html +++ /dev/null @@ -1,97 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - 12-Factor Apps - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 last"> - - 12factor - - </li> - - </ol> - - - - <div id="article"> - <h1 id="12-factor-apps">12-Factor Apps</h1> -<p>Some folks over at <a href="http://heroku.com/">Heroku</a> wrote up their perceived best -practices for building “software as a service”-style applications and called -it <a href="http://www.12factor.net">The Twelve-Factor App</a>. It's a good read, and has -lots of good advice in it.</p> -<p>I have a few thoughts on it.</p> -<hr> -<ul> -<li><a href="3-config">III. Config</a></li> -<li><a href="7-port-binding">VII. Port Binding</a></li> -</ul> -<hr> -<p>At some point around sections 6 or 7, the goodness of the advice is overtaken -by the “be more like Heroku specifically”-ness of the advice, to the detriment -of their point.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/12factor/index.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/12factor/index.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/_list.html b/.html/_list.html deleted file mode 100644 index 503621a..0000000 --- a/.html/_list.html +++ /dev/null @@ -1,130 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls / - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="./">index</a> - - </li> - - <li class="crumb-1 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /</code></h1> - - - <div id="directories"> - <h2>Directories</h2> - <ul> - - <li><a href="12factor/">12factor/</a></li> - - <li><a href="authnz/">authnz/</a></li> - - <li><a href="dev/">dev/</a></li> - - <li><a href="devops/">devops/</a></li> - - <li><a href="ethics/">ethics/</a></li> - - <li><a href="git/">git/</a></li> - - <li><a href="gossamer/">gossamer/</a></li> - - <li><a href="gpg/">gpg/</a></li> - - <li><a href="java/">java/</a></li> - - <li><a href="media/">media/</a></li> - - <li><a href="muds/">muds/</a></li> - - <li><a href="mysql/">mysql/</a></li> - - <li><a href="people/">people/</a></li> - - <li><a href="toronto/">toronto/</a></li> - - </ul> - </div> - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="cool-urls-can-change">Cool URLs Do Change (Sometimes)</a></li> - - <li><a href="hire-me">Hire Me</a></li> - - <li><a href="email">Why I Didn't Answer Your Email</a></li> - - <li><a href="packaging-ideas">Why “Web 2.0” Matters</a></li> - - </ul> - </div> - - - - <div id="files"> - <h2>Files</h2> - - <li><a href="keybase.txt">keybase.txt</a></li> - - </div> - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/authnz/_list.html b/.html/authnz/_list.html deleted file mode 100644 index c7948ab..0000000 --- a/.html/authnz/_list.html +++ /dev/null @@ -1,88 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /authnz - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">authnz</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /authnz</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="users-rolegraph-privs">A Users, Roles & Privileges Scheme Using Graphs</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/authnz">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/authnz/index.html b/.html/authnz/index.html deleted file mode 100644 index c7948ab..0000000 --- a/.html/authnz/index.html +++ /dev/null @@ -1,88 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /authnz - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">authnz</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /authnz</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="users-rolegraph-privs">A Users, Roles & Privileges Scheme Using Graphs</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/authnz">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/authnz/users-rolegraph-privs.html b/.html/authnz/users-rolegraph-privs.html deleted file mode 100644 index 79e1bbe..0000000 --- a/.html/authnz/users-rolegraph-privs.html +++ /dev/null @@ -1,197 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - A Users, Roles & Privileges Scheme Using Graphs - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">authnz</a> - - </li> - - <li class="crumb-2 last"> - - users-rolegraph-privs - - </li> - - </ol> - - - - <div id="article"> - <h1 id="a-users-roles-privileges-scheme-using-graphs">A Users, Roles & Privileges Scheme Using Graphs</h1> -<p>The basic elements:</p> -<ul> -<li>Every agent that can interact with a system is represented by a <strong>user</strong>.</li> -<li>Every capability the system has is authorized by a distinct <strong>privilege</strong>.</li> -<li>Each user has a list of zero or more <strong>roles</strong>.<ul> -<li>Roles can <strong>imply</strong> further roles. This relationship is transitive: if - role A implies role B, then a member of role A is a member of role B; if - role B also implies role C, then a member of role A is also a member of - role C. It helps if the resulting role graph is acyclic, but it's not - necessary.</li> -<li>Roles can <strong>grant</strong> privileges.</li> -</ul> -</li> -</ul> -<p>A user's privileges are the union of the privileges granted by the transitive -closure of their roles.</p> -<h2 id="in-sql">In SQL</h2> -<pre><code>create table "user" ( - username varchar - primary key - -- credentials &c -); - -create table role ( - name varchar - primary key -); - -create table role_member ( - role varchar - not null - references role, - member varchar - not null - references "user", - primary key (role, member) -); - -create table role_implies ( - role varchar - not null - references role, - implied_role varchar - not null -); - -create table privilege ( - privilege varchar - primary key -); - -create table role_grants ( - role varchar - not null - references role, - privilege varchar - not null - references privilege, - primary key (role, privilege) -); -</code></pre> -<p>If your database supports recursive CTEs, querying this isn't awful, since we -can have the database do all the graph-walking along roles:</p> -<pre><code>with recursive user_roles (role) AS ( - select - role - from - role_member - where - member = 'SOME USERNAME' - union - select - implied_role as role - from - user_roles - join role_implies on - user_roles.role = role_implies.role -) -select distinct - role_grants.privilege as privilege -from - user_roles - join role_grants on - user_roles.role = role_grants.role -order by privilege; -</code></pre> -<p>If not, get a better database. Recursive graph walking with network round -trips at each step is stupid and you shouldn't do it.</p> -<p>Realistic uses should have fairly simple graphs: elemental privileges are -grouped into abstract roles, which are in turn grouped into meaningful roles -(by department, for example), which are in turn granted to users. In -PostgreSQL, the above schema handles ~10k privileges and ~10k roles with -randomly-generated graph relationships in around 100ms on my laptop, which is -pretty slow but not intolerable. Perverse cases (interconnected total -subgraphs, deeply-nested linear graphs) can take absurd time but do not -reflect any likely permissions scheme.</p> -<h2 id="what-sucks">What Sucks</h2> -<ul> -<li>Graph theory in my authorization system? It's more likely than you think.</li> -<li>There's no notion of revoking a privilege. If you have a privilege by any - path through your roles, then it cannot be revoked except by removing all of - the paths that lead back to that privilege.</li> -<li>Not every system has an efficient way to compute these graphs.<ul> -<li>PostgreSQL, as given above, has a hard time with unrealistically-deep - nested roles.</li> -</ul> -</li> -</ul> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/authnz/users-rolegraph-privs.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/authnz/users-rolegraph-privs.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/cool-urls-can-change.html b/.html/cool-urls-can-change.html deleted file mode 100644 index f61f8e4..0000000 --- a/.html/cool-urls-can-change.html +++ /dev/null @@ -1,142 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Cool URLs Do Change (Sometimes) - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="./">index</a> - - </li> - - <li class="crumb-1 last"> - - cool-urls-can-change - - </li> - - </ol> - - - - <div id="article"> - <h1 id="cool-urls-do-change-sometimes">Cool URLs Do Change (Sometimes)</h1> -<p>Required reading: <a href="http://www.w3.org/Provider/Style/URI.html">Cool URLs don't -change</a>.</p> -<p>When I wrote <a href="http://codex.grimoire.ca/2008/09/24/nobody-cares-about-your-build/">Nobody Cares About Your -Build</a>, I -set up a dedicated publishing platform - Wordpress, as it happens - to host -it, and as part of that process I put some real thought into the choice of -“permalink” schemes to use. I opted to use a “dated” scheme, baking the -publication date of each article into its name - into its URL - for all -eternity. I'm a big believer in the idea that a URL should be a long-term name -for the appropriate bit of data or content, and every part of a dated scheme -“made sense” at the time.</p> -<p>This turned out to be a mistake.</p> -<p>The web is not, much, like print media. Something published may be amended; -you don't even have to publish errata or a correction, since you can correct -the original mistake “seamlessly.” This has its good and its -<a href="http://en.wikipedia.org/wiki/Memory_hole">bad</a> parts, but with judicious use -and <a href="https://github.com/ojacobson/grimoiredotca">a public history</a>, amendment -is more of a win than a loss. However, this plays havoc with the idea of a -“publication” date, even for data that takes the form of an article: is the -publication date the date it was first made public, the date of its most -recent edit, or some other date?</p> -<p>Because the name - the URL - of an article was set when I first published it, -the date in the name had to be its initial publication date. <em>This has -actually stopped me from making useful amendments to old articles</em> because the -effort of writing a full, free-standing followup article is more than I'm -willing to commit to. Had I left the date out of the URLs, I'd feel more free -to judiciously amend articles in place and include, in the content, a short -amendment summary.</p> -<p>The W3C's informal suggestions on the subject state that “After the creation -date, putting any information in the name is asking for trouble one way or -another.” I'm starting to believe that this doesn't go far enough: <em>every</em> -part of a URL must have some semantic justification for being there, dates -included:</p> -<ol> -<li> -<p><em>Each part must be meaningful</em>. While - <code>http://example.com/WW91IGp1c3QgbG9zdCB0aGUgZ2FtZQ==</code> is fairly easy to - render stable, the meaningless blob renders the name immemorable.</p> -</li> -<li> -<p><em>Each part must be stable</em>. This is where I screwed up worst: I did not - anticipate that the “date” of an article could be a fluid thing. It's - tempting to privilege the first date, and it's not an unreasonable - solution, but it didn't fit how I wanted to address the contents of - articles.</p> -</li> -</ol> -<p>Running a web server gives you one namespace to play with. Use it wisely.</p> -<h2 id="ok-but-ive-already-got-these-urls">Ok, But I've Already Got These URLs</h2> -<p>Thankfully, there's a way out - for <em>some</em> URLs. URLs inherently name -resources <em>accessed using some protocol</em>, and some protocols provide support -for resources that are, themselves, references to other URLs. HTTP is a good -example, providing a fairly rich set of responses that all, fundamentally, -tell a client to check a second URL for the content relevent to a given URL. -In protocols like this, you can easily replace the content of a URL with a -reference to its new, “better” URL rather than abandoning it entirely.</p> -<p>Names can evolve organically as the humans that issue them grow a better -understanding of the problem, and don't always have to be locked in stone from -the moment they're first used.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/cool-urls-can-change.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/cool-urls-can-change.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/_list.html b/.html/dev/_list.html deleted file mode 100644 index f242c8e..0000000 --- a/.html/dev/_list.html +++ /dev/null @@ -1,122 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /dev - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /dev</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="twigs">Branches and Twigs</a></li> - - <li><a href="trackers-from-first-principles">Bugs, Tasks, and Tickets from First Principles</a></li> - - <li><a href="comments">Comment Maturity Model</a></li> - - <li><a href="entry-points">Entry Points</a></li> - - <li><a href="shutdown-hooks">Falsehoods Programmers Believe About Shutdown Hooks</a></li> - - <li><a href="debugger-101">Intro to Debuggers</a></li> - - <li><a href="liquibase">Liquibase</a></li> - - <li><a href="merging-structural-changes">Merging Structural Changes</a></li> - - <li><a href="builds">Nobody Cares About Your Build</a></li> - - <li><a href="buffers">Observations on Buffering</a></li> - - <li><a href="rich-shared-models">Rich Shared Models Must Die</a></li> - - <li><a href="webapp-versions">Semver Is Wrong For Web Applications</a></li> - - <li><a href="whats-wrong-with-jenkins">Something's Rotten in the State of Jenkins</a></li> - - <li><a href="stop-building-synchronous-web-containers">Stop Building Synchronous Web Containers</a></li> - - <li><a href="gnu-collective-action-license">The GPL As Collective Action</a></li> - - <li><a href="webapps">Webapps From The Ground Up</a></li> - - <li><a href="why-scm">Why we use SCM systems</a></li> - - <li><a href="commit-messages">Writing Good Commit Messages</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/buffers.html b/.html/dev/buffers.html deleted file mode 100644 index 839eefd..0000000 --- a/.html/dev/buffers.html +++ /dev/null @@ -1,202 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Observations on Buffering - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - buffers - - </li> - - </ol> - - - - <div id="article"> - <h1 id="observations-on-buffering">Observations on Buffering</h1> -<p>None of the following is particularly novel, but the reminder has been useful:</p> -<ul> -<li> -<p>All buffers exist in one of two states: full (writes outpace reads), or empty - (reads outpace writes). There are no other stable configurations.</p> -</li> -<li> -<p>Throughput on an empty buffer is dominated by the write rate. Throughput on a - full buffer is dominated by the read rate.</p> -</li> -<li> -<p>A full buffer imposes a latency penalty equal to its size in bits, divided by - the read rate in bits per second. An empty buffer imposes (approximately) no - latency penalty.</p> -</li> -</ul> -<p>The previous three points suggest that <strong>traffic buffers should be measured in -seconds, not in bytes</strong>, and managed accordingly. Less obviously, buffer -management needs to be considerably more sophisticated than the usual "grow -buffer when full, up to some predefined maximum size."</p> -<p>Point one also implies a rule that I see honoured more in ignorance than in -awareness: <strong>you can't make a full buffer less full by making it bigger</strong>. Size -is not a factor in buffer fullness, only in buffer latency, so adjusting the -size in response to capacity pressure is worse than useless.</p> -<p>There are only three ways to make a full buffer less full:</p> -<ol> -<li> -<p>Increase the rate at which data exits the buffer.</p> -</li> -<li> -<p>Slow the rate at which data enters the buffer.</p> -</li> -<li> -<p>Evict some data from the buffer.</p> -</li> -</ol> -<p>In actual practice, most full buffers are upstream of some process that's -already going as fast as it can, either because of other design limits or -because of physics. A buffer ahead of disk writing can't drain faster than the -disk can accept data, for example. That leaves options two and three.</p> -<p>Slowing the rate of arrival usually implies some variety of <em>back-pressure</em> on -the source of the data, to allow upstream processes to match rates with -downstream processes. Over-large buffers delay this process by hiding -back-pressure, and buffer growth will make this problem worse. Often, -back-pressure can happen automatically: failing to read from a socket, for -example, will cause the underlying TCP stack to apply back-pressure to the peer -writing to the socket by delaying TCP-level message acknowledgement. Too often, -I've seen code attempt to suppress these natural forms of back-pressure without -replacing them with anything, leading to systems that fail by surprise when -some other resource – usually memory – runs out.</p> -<p>Eviction relies on the surrounding environment, and must be part of the -protocol design. Surprisingly, most modern application protocols get very -unhappy when you throw their data away: the network age has not, sadly, brought -about protocols and formats particularly well-designed for distribution.</p> -<p>If neither back-pressure nor eviction are available, the remaining option is to -fail: either to start dropping data unpredictably, or to cease processing data -entirely as a result of some resource or another running out, or to induce so -much latency that the data is useless by the time it arrives.</p> -<hr> -<p>Some uncategorized thoughts:</p> -<ul> -<li> -<p>Some buffers exist to trade latency against the overhead of coordination. A - small buffer in this role will impose more coordination overhead; a large - buffer will impose more latency.</p> -<ul> -<li> -<p>These buffers appear where data transits between heterogenous system: for - example, buffering reads from the network for writes to disk.</p> -</li> -<li> -<p>Mismanaged buffers in this role will tend to cause the system to spend - an inordinate proportion of latency and throughput negotiating buffer - sizes and message readiness.</p> -</li> -<li> -<p>A coordination buffer is most useful when <em>empty</em>; in the ideal case, the - buffer is large enough to absorb one message's worth of data from the - source, then pass it along to the sink as quickly as possible.</p> -</li> -</ul> -</li> -<li> -<p>Some buffers exist to trade latency against jitter. A small buffer in this - role will expose more jitter to the upstream process. A large buffer in this - role will impose more latency.</p> -<ul> -<li> -<p>These tend to appear in <em>homogenous</em> systems with differing throughputs, - or as a consequence of some other design choice. Store-and-forward - switching in networks, for example, implies that switches must buffer at - least one full frame of network data.</p> -</li> -<li> -<p>Mis-managed buffers in this role will <em>amplify</em> rather than smoothing out - jitter. Apparent throughput will be high until the buffer fills, then - change abruptly when full. Upstream processes are likely to throttle - down, causing them to under-deliver if the buffer drains, pushing the - system back to a high-throughput mode. <a href="http://www.bufferbloat.net">This problem gets worse the - more buffers are present in a system</a>.</p> -</li> -<li> -<p>An anti-jitter buffer is most useful when <em>full</em>; in exchange for a - latency penalty, sudden changes in throughput will be absorbed by data - in the buffer rather than propagating through to the source or sink.</p> -</li> -</ul> -</li> -<li> -<p>Multimedia people understand this stuff at a deep level. Listen to them when - designing buffers for other applications.</p> -</li> -</ul> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/buffers.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/buffers.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/builds.html b/.html/dev/builds.html deleted file mode 100644 index 5626a4e..0000000 --- a/.html/dev/builds.html +++ /dev/null @@ -1,270 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Nobody Cares About Your Build - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - builds - - </li> - - </ol> - - - - <div id="article"> - <h1 id="nobody-cares-about-your-build">Nobody Cares About Your Build</h1> -<p>Every software system, from simple Python packages to huge enterprise-grade -systems spanning massive clusters, has a build—a set of steps that must be -followed to go from a source tree or a checked-out project to a ready-to-use -build product. A build system's job is to automate these steps.</p> -<p>Build systems are critical to software development.</p> -<p>They're also one of the most common avoidable engineering failures.</p> -<p>A reliable, comfortable build system has measurable benefits for software -development. Being able to build a testable, deployable system at any point -during development lets the team test more frequently. Frequent testing -isolates bugs and integration problems earlier, reducing their impact. Simple, -working builds allow new team members to ramp up more quickly on a project: -once they understand how one piece of the system is constructed, they can -apply that knowledge to the entire system and move on to doing useful work. If -releases, the points where code is made available outside the development -team, are done using the same build system that developers use in daily life, -there will be fewer surprises during releases as the “release” build process -will be well-understood from development.</p> -<h2 id="builds-have-needs-too">Builds Have Needs, Too</h2> -<p>In 1947, Abraham Maslow described a <a href="http://en.wikipedia.org/wiki/Maslow's_hierarchy_of_needs">hierarchy of -needs</a> for a -person's physical and mental well-being on the premise that all the items at -the lowest level of the hierarchy must be met before a person will be able to -focus usefully on higher-level needs. Maslow's hierarchy begins with a set of -needs that, without which, you do not have a person (for long)—physiological -needs like “breathing,” “food,” and “water.” At the peak, there are extremely -high-level needs that are about being a happy and enlightened -person—“creativity,” “morality,” “curiosity,” and so on.</p> -<p><img alt="A three-tier pyramid. At the bottom: Automatable. Repeatable. Standardized. -Extensible. Understood. In the middle tier: Simple. Fast. Unit tests. Part of -the project. Environment independent. At the top: Metrics. Parallel builds. -Acceptance tests. Product caching. IDE -integration." src="/media/dev/builds/buildifesto-pyramid.png"></p> -<p>Builds, and software engineering as a whole, can be described the same way: at -the top of the hierarchy is a working system that solves a problem, and at the -bottom are the things you need to have software at all. If you don't meet -needs at a given level, you will eventually be forced to stop what you're -doing at a higher level and face them.</p> -<p>Before a build is a build, there are five key needs to meet:</p> -<ul> -<li><strong>It must be repeatable</strong>. Every time you start your build on a given source - tree, it must build exactly the same products without any further - intervention. Without this, you can't reliably decide whether a given build - is “good,” and can easily wind up with a build that needs to be run several - times, or a build that relies on running several commands in the right - order, to produce a build.</li> -<li><strong>It must be automatable</strong>. Build systems are used by developers sitting at - their desks, but they’re also used by automatic build systems for nightly - builds and continuous integration, and they can be made into parts of other - builds. A build system that can only be run by having someone sit down at a - keyboard and mouse and kicking it off can’t be integrated into anything - else.</li> -<li><strong>It must be standardized</strong>. If you have multiple projects that build - similar things—for example, several Java libraries—all of them must be built - the same way. Without this, it's difficult for a developer to apply - knowledge from one project to another, and it's difficult to debug problems - with individual builds.</li> -<li><strong>It must be extensible</strong>. Not all builds are created equal. Where one build - compiles a set of source files, another needs five libraries and a WSDL - descriptor before it can compile anything. There must be affordances within - the standard build that allow developers to describe the ways their build is - different. Without this, you have to write what amounts to a second build - tool to ensure that all the “extra” steps for certain projects happen.</li> -<li><strong>Someone must understand it</strong>. A build nobody understands is a time bomb: - when it finally breaks (and it will), your project will be crippled until - someone fixes it or, more likely, hacks around it.</li> -</ul> -<p>If you have these five things, you have a working build. The next step is to -make it comfortable. Comfortable builds can be used daily for development -work, demonstrations, and tests as well as during releases; builds that are -used constantly don't get a chance to “rust” as developers ignore them until a -release or a demo and don’t hide surprises for launch day.</p> -<ul> -<li><strong>It must be simple</strong>. When a complicated build breaks, you need someone who - understands it to fix it for you. Simple builds mean more people can - understand it and fewer things can break.</li> -<li><strong>It must be fast</strong>. A slow build will be hacked around or ignored entirely. - Ideally, someone creating a local build for a small change should have a - build ready in seconds.</li> -<li><strong>It must be part of the product</strong>. The team responsible for developing a - project must be in control of and responsible for its build. Changes to it - and bugs against it must be treated as changes to the product or bugs in the - product.</li> -<li><strong>It must run unit tests</strong>. Unit tests, which are completely isolated tests - written by and for developers, can catch a large number of bugs, but they're - only useful if they get run. The build must run the unit test suite for the - product it's building every build.</li> -<li><strong>It must build the same thing in any environment</strong>. A build is no good if - developers can only get a working build from a specific machine, or where a - build from one developer's machine is useless anywhere else. If the build is - uniform on any environment, any developer can cook up a build for a test or - demo at any time.</li> -</ul> -<p>Finally, there are “chrome” features that take a build from effective to -excellent. These vary widely from project to project and from organization to -organization. Here are some common chrome needs:</p> -<ul> -<li><strong>It should integrate with your IDEs</strong>. This goes both directions: it should - be possible to run the build without leaving your IDE or editor suite, and - it should be possible to translate the build system into IDE-specific - configurations to reduce duplication between IDE settings and the build - configuration.</li> -<li><strong>It should generate metrics</strong>. If you gather metrics for test coverage, - common bugs, complexity analysis, or generate reports or documentation, the - build system should be responsible for it. This keeps all the common - administrative actions for the project in the same place as the rest of the - configuration, and provides the same consistency that the system gives the - rest of the build.</li> -<li><strong>It should support multiple processors</strong>. For medium-sized builds that - aren’t yet large enough to merit breaking down into libraries, being able to - perform independent build steps in parallel can be a major time-saver. This - can extend to distributed build systems, where idle CPU time can be donated - to other peoples’ builds.</li> -<li><strong>It should run integration and acceptance tests</strong>. Taking manual work from - the quality control phase of a project and running it automatically during - builds amplifies the benefits of early testing and, if your acceptance tests - are good, when your project is done.</li> -<li><strong>It should not need repeating</strong>. Once you declare a particular set of build - products “done,” you should be able to use those products as-is any time you - need them. Without this, you will eventually find yourself rebuilding the - same code from the same release over and over again.</li> -</ul> -<h2 id="what-doesnt-work">What Doesn’t Work</h2> -<p>Builds, like any other part of software development, have -antipatterns—recurring techniques for solving a problem that introduce more -problems.</p> -<ul> -<li><strong>One Source Tree, Many Products</strong>. Many small software projects that - survive to grow into large, monolithic projects are eventually broken up - into components. It's easy to do this by taking the existing source tree and - building parts of it, and it's also wrong. Builds that slice up a single - source tree require too much discipline to maintain and too much mental - effort to understand. Break your build into separate projects that are built - separately, and have each build produce one product.</li> -<li><strong>The Build And Deploy System</strong>. Applications that have a server component - often choose to automate deployment and setup using the same build system - that builds the project. Too often, the extra build steps that set up a - working system from the built project are tacked onto the end of an existing - build. This breaks standardization, making that build harder to understand, - and means that that one build is producing more than one thing—it's - producing the actual project, and a working system around the project.</li> -<li><strong>The Build Button</strong>. IDEs are really good at editing code. Most of them - will produce a build for you, too. Don't rely on IDE builds for your build - system, and don't let the IDE reconfigure the build process. Most IDEs don't - differentiate between settings that apply to the project and settings that - apply to the local environment, leading to builds that rely on libraries or - other projects being in specific places and on specific IDE settings that - are often buried in complex settings dialogs.</li> -<li><strong>Manual Steps</strong>. Anything that gets done by hand will eventually be done - wrong. Automate every step.</li> -</ul> -<h2 id="what-does-work">What Does Work</h2> -<p>Similarly, there are patterns—solutions that recur naturally and can be -applied to many problems.</p> -<ul> -<li><strong>Do One Thing Well</strong>. The UNIX philosophy of small, cohesive tools works - for build systems, too: if you need to build a package, and then install it - on a server, write three builds: one that builds the package, one that takes - a package and installs it, and a third that runs the first two builds in - order. The individual builds will be small enough to easily understand and - easy to standardize, and the package ends up installed on the server when - the main build finishes.</li> -<li><strong>Dependency Repositories</strong>. After a build is done, make the built product - available to other builds and to the user for reuse rather than rebuilding - it every time you need it. Similarly, libraries and other inward - dependencies for a build can be shared between builds, reducing duplication - between projects.</li> -<li><strong>Convention Over Extension</strong>. While it's great that your build system is - extensible, think hard about whether you really need to extend your build. - Each extension makes that project’s build that much harder to understand and - adds one more point of failure.</li> -</ul> -<h2 id="pick-a-tool-any-tool">Pick A Tool, Any Tool</h2> -<p>Nothing here is new. The value of build systems has been -<a href="http://www.joelonsoftware.com/articles/fog0000000043.html">discussed</a> -<a href="http://www.gamesfromwithin.com/articles/0506/000092.html">in</a> -<a href="http://c2.com/cgi/wiki?BuildSystem">great</a> -<a href="http://www.codinghorror.com/blog/archives/000988.html">detail</a> elsewhere. -Much of the accumulated build wisdom of the software industry has already been -incorporated to one degree or another into build tools. What matters is that -you pick one, then use it with the discipline needed to get repeatable results -without thinking.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/builds.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/builds.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/comments.html b/.html/dev/comments.html deleted file mode 100644 index 4f891c9..0000000 --- a/.html/dev/comments.html +++ /dev/null @@ -1,98 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Comment Maturity Model - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - comments - - </li> - - </ol> - - - - <div id="article"> - <h1 id="comment-maturity-model">Comment Maturity Model</h1> -<blockquote> -<ul> -<li>Beginners comment nothing</li> -<li>Apprentices comment the obvious</li> -<li>Journeymen comment the reason for doing it</li> -<li>Masters comment the reason for not doing it another way</li> -</ul> -</blockquote> -<p>Richard C. Haven, via <a href="http://cluefire.net/">cluefire.net</a></p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/comments.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/comments.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/commit-messages.html b/.html/dev/commit-messages.html deleted file mode 100644 index 45a580e..0000000 --- a/.html/dev/commit-messages.html +++ /dev/null @@ -1,163 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Writing Good Commit Messages - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - commit-messages - - </li> - - </ol> - - - - <div id="article"> - <h1 id="writing-good-commit-messages">Writing Good Commit Messages</h1> -<p>Rule zero: “good” is defined by the standards of the project you're on. Have a -look at what the existing messages look like, and try to emulate that first -before doing anything else.</p> -<p>Having said that, here are some things that will help your commit messages be -useful later:</p> -<ul> -<li> -<p>Treat the first line of the message as a one-sentence summary. Most SCM - systems have an “overview” command that shows shortened commit messages in - bulk, so making the very beginning of the message meaningful helps make - those modes more useful for finding specific commits. <em>It's okay for this to - be a “what” description</em> if the rest of the message is a “why” description.</p> -</li> -<li> -<p>Fill out the rest of the message with prose outlining why you made the - change. The guidelines for a good “why” message are the same as <a href="comments">the - guidelines for good comments</a>, but commit messages can be - signifigantly longer. Don't bother reiterating the contents of the change in - detail; anyone who needs that can read the diff themselves.</p> -</li> -<li> -<p>If you use an issue tracker (and you should), include whatever issue-linking - notes it supports right at the start of the message, where it'll be visible - even in shortlogs. If your tracker has absurdly long issue-linking syntax, - or doesn't support issue links in commits at all, include a short issue - identifier at the front of the message and put the long part somewhere out - of the way, such as on a line of its own at the end of the message.</p> -</li> -<li> -<p>Pick a tense and a mood and stick with them. Reading one commit with a - present-tense imperative message (“Add support for PNGs”) and another commit - with a past-tense narrative message (“Fixed bug in PNG support”) is - distracting.</p> -</li> -<li> -<p>If you need rich commit messages (links, lists, and so on), pick one markup - language and stick with it. It'll be easier to write useful commit - formatters if you only have to deal with one syntax, rather than four. - (Personally, I use Markdown on projects I control.)</p> -<ul> -<li>This also applies to line-wrapping: either hard-wrap everywhere, or - hard-wrap nowhere.</li> -</ul> -</li> -</ul> -<h2 id="an-example">An Example</h2> -<pre><code>commit 842e6c5f41f6387781fcc84b59fac194f52990c7 -Author: Owen Jacobson <owen.jacobson@grimoire.ca> -Date: Fri Feb 1 16:51:31 2013 -0500 - - DS-37: Add support for privileges, and create a default privileged user. - - This change gives each user a (possibly empty) set of privileges. Privileges - are mediated by roles in the following ways: - - * Each user is a member of zero or more roles. - * Each role implies membership in zero or more roles. If role A implies role - B, then a member of role A is also a transitive member of role B. This - relationship is transitive: if A implies B and B implies C, then A implies - C. This graph should not be cyclic, but it's harmless if it is. - * Each role grants zero or more privileges. - - A user's privileges are the union of all privileges of all roles the user is a - member of, either directly or transitively. - - Obviously, a role that implies no other roles and grants no priveleges is - meaningless to the authorization system. This may be useful for "advisory" - roles meant for human consumption. - - This also introduces a user with the semi-magical name '*admin' (chosen - because asterisks cannot collide with player-chosen usernames), and the group - '*superuser' that is intended to hold all privileges. No privileges are yet - defined. -</code></pre> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/commit-messages.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/commit-messages.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/debugger-101.html b/.html/dev/debugger-101.html deleted file mode 100644 index a19476a..0000000 --- a/.html/dev/debugger-101.html +++ /dev/null @@ -1,178 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Intro to Debuggers - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - debugger-101 - - </li> - - </ol> - - - - <div id="article"> - <h1 id="intro-to-debuggers">Intro to Debuggers</h1> -<p>(Written largely because newbies in <a href="http://evanchooly.com">##java</a> never seem -to have this knowledge.)</p> -<p>A “debugger” is a mechanism for monitoring and controlling the execution of -your program, usually interactively. Using a debugger, you can stop your -program at known locations and examine the <em>actual</em> values of its variables -(to compare against what you expected), monitor variables for changes (to see -where they got the values they have, and why), and step through code a line at -a time (to watch control flow and verify that it matches your expectations).</p> -<p>Pretty much every worthwhile language has debugging support of some kind, -whether it's via IDE integration or via a command-line debugger.</p> -<p>(Of course, none of this helps if you don't have a mental model of the -“expected” behaviour of the program. Debuggers can help you read, but can't -replace having an understanding of the code.)</p> -<h2 id="debugging-your-first-program">Debugging Your First Program</h2> -<p>Generally, you start running a debugger because you have a known problem -- an -exception, or code behaving strangely -- somewhere in your program that you -want to investigate more closely. Start by setting a <em>breakpoint</em> in your -program at a statement slightly before the problem area.</p> -<p>Breakpoints are instructions to the debugger, telling it to stop execution -when the program reaches the statement the breakpoint is set on.</p> -<p>Run the program in the debugger. When it reaches your breakpoint, execution -will stop (and your program will freeze, rather than exiting). You can now -<em>inspect</em> values and run expressions in the context of your program in its -current state. Depending on the debugger and the platform, you may be able to -modify those values, too, to quickly experiment with the problem and attempt -to solve it.</p> -<p>Once you've looked at the relevant variables, you can resume executing your -program - generally in one of five ways:</p> -<ul> -<li> -<p><em>Continue</em> execution normally. The debugger steps aside until the program - reaches the next breakpoint, or exits, and your program executes normally.</p> -</li> -<li> -<p>Execute the <em>next</em> statement. Execution proceeds for one statement in the - current function, then stops again. If the statement is, for example, a - function or method call, the call will be completely evaluated (unless it - contains breakpoints of its own). (In some debuggers, this is labelled “step - over,” since it will step “over” a function call.)</p> -</li> -<li> -<p><em>Step</em> forward one operation. Execution proceeds for one statement, then - stops again. This mode can single-step into function calls, rather than - letting them complete uninterrupted.</p> -</li> -<li> -<p><em>Continue to end of function</em>. The debugger steps aside until the program - reaches the end of the current function, then halts the program again.</p> -</li> -<li> -<p><em>Continue to a specific statement</em>. Some debuggers support this mode as a - way of stepping over or through “uninteresting” sections of code quickly and - easily. (You can implement this yourself with “Continue” and normal - breakpoints, too.)</p> -</li> -</ul> -<p>Whenever the debugger halts your program, you can do any of several things:</p> -<ul> -<li> -<p>Inspect the value of a variable or field, printing a useful representation - to the debugger. This is a more flexible version of the basic idea of - printing debug output as you go: because the program is stopped, you can - pick and choose which bits of information to look at on the fly, rather than - having to rerun your code with extra debug output.</p> -</li> -<li> -<p>Inspect the result of an expression. The debugger will evaluate an - expression “as if” it occurred at the point in the program where the - debugger is halted, including any local variables. In languages with static - visibility controls like Java, visibility rules are often relaxed in the - name of ease of use, allowing you to look at the private fields of objects. - The result of the expression will be made available for inspection, just - like a variable.</p> -</li> -<li> -<p>Modify a variable or field. You can use this to quickly test hypotheses: for - example, if you know what value a variable “should” have, you can set that - value directly and observe the behaviour of the program to check that it - does what you expected before fixing the code that sets the variable in a - non-debug run.</p> -</li> -<li> -<p>In some debuggers, you can run arbitrary code in the context of the halted - program.</p> -</li> -<li> -<p>Abort the program.</p> -</li> -</ul> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/debugger-101.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/debugger-101.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/entry-points.html b/.html/dev/entry-points.html deleted file mode 100644 index 717c320..0000000 --- a/.html/dev/entry-points.html +++ /dev/null @@ -1,134 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Entry Points - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - entry-points - - </li> - - </ol> - - - - <div id="article"> - <h1 id="entry-points">Entry Points</h1> -<p>The following captures a conversation from IRC:</p> -<blockquote> -<p><a href="https://twitter.com/derspiny">Owen J</a>: Have you run across the idea -of an "entry point" in a runtime yet? (You've definitely used it, just -possibly not known it had a name.)</p> -<p><a href="https://twitter.com/aeleitch">Alex L</a>: I have not!</p> -<p><a href="https://twitter.com/derspiny">Owen J</a>: It's the point where the -execution of the outside system -- the OS, the browser, the Node -runtime, whatever -- stops and the execution of your code starts. Some -platforms only give you one: C on Unix is classic, where there's only -two entry points: main and signal handlers (and a lot of apps only use -main). JS gives you <em>a shit fucking ton</em> of entry points.</p> -<p><a href="https://twitter.com/derspiny">Owen J</a>: In a browser, the pageload -process is an entry point: your code gets run when the browser -encounters a <code><script></code> tag. So is every event handler. There's none -of your code running when an event handler starts, only the browser -is running. So is every callback from an external service, like -<code>XmlHttpRequest</code> or <code>EventSource</code> or the <code>File</code> APIs. In Node, the top -level of your main script is an entry point, but so is every callback -from an external service.</p> -<p><a href="https://twitter.com/aeleitch">Alex L</a>: Ahahahahahahaha oh my -god. There is no way for me to contain them all. <em>everything the light -touches.</em></p> -<p><a href="https://twitter.com/derspiny">Owen J</a>: This is important for -reasoning about exception handling! <em>In JS</em>, exception handling only -propagates one direction: towards the entry point of this sequence of -function calls.</p> -<p><a href="https://twitter.com/aeleitch">Alex L</a>: Yes. This is what <em>I</em> call a -stack trace.</p> -<p><a href="https://twitter.com/derspiny">Owen J</a>: If an exception escapes from -an entry point, the JS runtime logs it, and then the outside runtime -takes over again. That's one of the ways callbacks from external -services fuck up the idea of a stack trace as a map of control flow.</p> -<p><a href="https://twitter.com/aeleitch">Alex L</a>: Huh. Yes. Yes I can see -that. I mean, in my world, control flow is a somewhat handwavey idea -right now. I'm starting to understand why so many people hate JS-land.</p> -<p><a href="https://twitter.com/derspiny">Owen J</a>: Sure. But, for example, a -promise chain is a tool for restructuring control flow. In principle, -error handling should provide <em>some</em> kind of map of that, to allow -programmers -- you -- to diagnose how a program reached a given error -state and maybe one day fix the problem. In THIS future, none of them -do that well, though.</p> -<p><a href="https://twitter.com/aeleitch">Alex L</a>: Yes. Truly the darkest -timeline, but this reviews why I am having these concerns.</p> -</blockquote> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/entry-points.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/entry-points.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/gnu-collective-action-license.html b/.html/dev/gnu-collective-action-license.html deleted file mode 100644 index f2adbea..0000000 --- a/.html/dev/gnu-collective-action-license.html +++ /dev/null @@ -1,133 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - The GPL As Collective Action - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - gnu-collective-action-license - - </li> - - </ol> - - - - <div id="article"> - <h1 id="the-gpl-as-collective-action">The GPL As Collective Action</h1> -<p>Programmers, like many groups of subject experts, are widely afflicted by the -belief that all other fields of expertise can be reduced to a special case of -programming expertise. For a great example of this, watch <a href="https://xkcd.com/1494/">programmers argue -about law</a> (which can <em>obviously</em> be reduced to a rules -system, which is a programming problem), -<a href="https://www.reddit.com/r/Bitcoin/comments/2e5a7k/could_the_blockchain_be_used_to_prove_consensual/">consent</a> -(which is <em>obviously</em> about non-repudiatable proofs, which are a programming -problem), or <a href="https://github.com/google/deepdream">art</a> (which is <em>obviously</em> -reducible to simple but large automata). One key symptom of this social pattern -is a disregard for outside expertise and outside bodies of knowledge.</p> -<p>I believe this habit may have bitten Stallman.</p> -<p>The GNU Public License presents a simple, legally enforceable offer: in return -for granting the right to distribute the licensed work and its derivatives, the -GPL demands that derivative works also be released under the GPL. The <em>intent</em>, -as derived from -<a href="http://www.gnu.org/philosophy/open-source-misses-the-point.en.html">Stallman’s commentaries</a> -on the GPL and on the social systems around software, is that people who <em>use</em> -information systems should, morally and legally, be entitled to the tools to -understand what the system will do and why, and to make changes to those tools -as they see fit.</p> -<p>This is a form of <em>collective action</em>, as implemented by someone who thinks of -unions and organized labour as something that software could do better. The -usual lens for critique of the GPL is that GPL’d software cannot be used in -non-GPL systems (which is increasingly true, as the Free Software Foundation -catches up with the “as a Service” model of software deliver) <em>by developers</em>, -but I think there’s a more interesting angle on it as an attempt to apply the -collective bargaining power of programmers as a class to extracting a -concession from managerial -- business and government -- interests, instead. In -that reading, the GPL demands that managerial interests in software avoid -behaviours that would be bad for programmers (framed as “users”, as above) as a -condition of benefitting from the labour of those programmers.</p> -<p>Sadly, Stallman is not a labour historian or a union organizer. He’s a public -speaker and a programmer. By attempting to reinvent collective action from -first principles, and by treating collective action as a special case of -software development, the GPL acts to divide programmers from non-programming -computer users, and to weaken the collective position of programmers vis-à-vis -managerial interests. The rise of “merit”-based open source licenses, such as -the MIT license (which I use heavily, but advisedly), and the increasing -pervasiveness of the Github Resume, are both simple consequences of this -mistake.</p> -<p>I’m pro-organized-labour, and largely pro-union. The only thing worse than -having two competing powerful interests in the room is having only one powerful -interest in the room. The GPL should be part of any historical case study for -the unionization of programmers, since it captures so much of what we do wrong.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/gnu-collective-action-license.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/gnu-collective-action-license.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/index.html b/.html/dev/index.html deleted file mode 100644 index f242c8e..0000000 --- a/.html/dev/index.html +++ /dev/null @@ -1,122 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /dev - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /dev</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="twigs">Branches and Twigs</a></li> - - <li><a href="trackers-from-first-principles">Bugs, Tasks, and Tickets from First Principles</a></li> - - <li><a href="comments">Comment Maturity Model</a></li> - - <li><a href="entry-points">Entry Points</a></li> - - <li><a href="shutdown-hooks">Falsehoods Programmers Believe About Shutdown Hooks</a></li> - - <li><a href="debugger-101">Intro to Debuggers</a></li> - - <li><a href="liquibase">Liquibase</a></li> - - <li><a href="merging-structural-changes">Merging Structural Changes</a></li> - - <li><a href="builds">Nobody Cares About Your Build</a></li> - - <li><a href="buffers">Observations on Buffering</a></li> - - <li><a href="rich-shared-models">Rich Shared Models Must Die</a></li> - - <li><a href="webapp-versions">Semver Is Wrong For Web Applications</a></li> - - <li><a href="whats-wrong-with-jenkins">Something's Rotten in the State of Jenkins</a></li> - - <li><a href="stop-building-synchronous-web-containers">Stop Building Synchronous Web Containers</a></li> - - <li><a href="gnu-collective-action-license">The GPL As Collective Action</a></li> - - <li><a href="webapps">Webapps From The Ground Up</a></li> - - <li><a href="why-scm">Why we use SCM systems</a></li> - - <li><a href="commit-messages">Writing Good Commit Messages</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/liquibase.html b/.html/dev/liquibase.html deleted file mode 100644 index 64b19c5..0000000 --- a/.html/dev/liquibase.html +++ /dev/null @@ -1,151 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Liquibase - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - liquibase - - </li> - - </ol> - - - - <div id="article"> - <h1 id="liquibase">Liquibase</h1> -<p>Note to self: I think this (a) needs an outline and (b) wants to become a “how -to automate db upgrades for dummies” page. Also, this is really old (~2008) -and many things have changed: database migration tools are more -widely-available and mature now. On the other hand, I still see a lot of -questions on IRC that are based on not even knowing these tools exist.</p> -<hr> -<p>Successful software projects are characterized by extensive automation and -supporting tools. For source code, we have version control tools that support -tracking and reviewing changes, marking particular states for release, and -automating builds. For databases, the situation is rather less advanced in a -lot of places: outside of Rails, which has some rather nice -<a href="http://wiki.rubyonrails.org/rails/pages/understandingmigrations">migration</a> -support, and <a href="http://code.google.com/p/django-evolution/">evolutions</a> or -<a href="http://south.aeracode.org">South</a> for Django, there are few tools that -actually track changes to the database or to the model in a reproducible way.</p> -<p>While I was exploring the problem by writing some scripts for my own projects, -I came to a few conclusions. You need to keep a receipt for the changes a -database has been exposed to in the database itself so that the database can -be reproduced later. You only need scripts to go forward from older versions -to newer versions. Finally, you need to view <abbr title="Data Definition Language">DDL</abbr> statements as a degenerate -form of diff, between two database states, that's not combinable the way -textual diff is except by concatenation.</p> -<p>Someone on IRC mentioned <a href="http://www.liquibase.org/">Liquibase</a> and -<a href="http://migrate4j.sourceforge.net/">migrate4j</a> to me. Since I was already in -the middle of writing a second version of my own scripts to handle the issues -I found writing the first version, I stopped and compared notes.</p> -<p>Liquibase is essentially the tool I was trying to write, only with two years -of relatively talented developer time poured into it rather than six weeks.</p> -<p>Liquibase operates off of a version table it maintains in the database itself, -which tracks what changes have been applied to the database, and off of a -configuration file listing all of the database changes. Applying new changes -to a database is straightforward: by default, it goes through the file and -applies all the changes that are in the file that are not already in the -database, in order. This ensures that incremental changes during development -are reproduced in exactly the same way during deployment, something lots of -model-to-database migration tools have a problem with.</p> -<p>The developers designed the configuraton file around some of the ideas from -<a href="http://www.amazon.com/Refactoring-Databases-Evolutionary-Addison-Wesley-Signature/dp/0321293533">Refactoring -Databases</a>, -and provided an <a href="http://www.liquibase.org/manual/home#available_database_refactorings">extensive list of canned -changes</a> -as primitives in the database change scripts. However, it's also possible to -insert raw SQL commands (either <abbr title="Data Definition Language">DDL</abbr>, or <abbr title="Data Manipulation Language">DML</abbr> queries like <code>SELECT</code>s and -<code>INSERT</code>s) at any point in the change sequence if some change to the database -can't be accomplished with its set of refactorings. For truly hairy databases, -you can use either a Java class implementing your change logic or a shell -script alongside the configuration file.</p> -<p>The tools for applying database changes to databases are similarly flexible: -out of the box, liquibase can be embedded in a fairly wide range of Java -applications using servlet context listeners, a Spring adapter, or a Grails -adapter; it can also be run from an ant or maven build, or as a standalone -tool.</p> -<p>My biggest complaint is that liquibase is heavily Java-centric; while the -developers are planning .Net support, it'd be nice to use it for Python apps -as well. Triggering liquibase upgrades from anything other than a Java program -involves either shelling out to the <code>java</code> command or creating a JVM and -writing native glue to control the upgrade process, which are both pretty -painful. I'm also less than impressed with the javadoc documentation; while -the manual is excellent, the javadocs are fairly incomplete, making it hard to -write customized integrations.</p> -<p>The liquibase developers deserve a lot of credit for solving a hard problem -very cleanly.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/liquibase.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/liquibase.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/merging-structural-changes.html b/.html/dev/merging-structural-changes.html deleted file mode 100644 index a019d9c..0000000 --- a/.html/dev/merging-structural-changes.html +++ /dev/null @@ -1,156 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Merging Structural Changes - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - merging-structural-changes - - </li> - - </ol> - - - - <div id="article"> - <h1 id="merging-structural-changes">Merging Structural Changes</h1> -<p>In 2008, a project I was working on set out to reinvent their build process, -migrating from a mass of poorly-written Ant scripts to Maven and reorganizing -their source tree in the process. The development process was based on having -a branch per client, so there was a lot of ongoing development on the original -layout for clients that hadn't been migrated yet. We discovered that our -version control tool, <a href="http://subversion.tigris.org/">Subversion</a>, was unable -to merge the changes between client branches on the old structure and the -trunk on the new structure automatically.</p> -<p>Curiousity piqued, I cooked up a script that reproduces the problem and -performs the merge from various directions to examine the results. Subversion, -sadly, performed dismally: none of the merge scenarios tested retained content -changes when merging structural changes to the same files.</p> -<h2 id="the-preferred-outcome">The Preferred Outcome</h2> -<p><img alt="Both changes survive the -merge." src="/media/dev/merging-structural-changes/ideal-merge-results.png"></p> -<p>The diagram above shows a very simple source tree with one directory, <code>dir-a</code>, -containing one file with two lines in it. On one branch, the file is modified -to have a third line; on another branch, the directory is renamed to <code>dir-b</code>. -Then, both branches are merged, and the resulting tree contains both sets of -changes: the file has three lines, and the directory has a new name.</p> -<p>This is the preferred outcome, as no changes are lost or require manual -merging.</p> -<h2 id="subversion">Subversion</h2> -<p><img alt="Subversion loses the content -change." src="/media/dev/merging-structural-changes/subversion-merge-results.png"></p> -<p>There are two merge scenarios in this diagram, with almost the same outcome. -On the left, a working copy of the branch where the file's content changed is -checked out, then the changes from the branch where the structure changed are -merged in. On the right, a working copy of the branch where the structure -changed is checked out, then the changes from the branch where the content -changed are merged in. In both cases, the result of the merge has the new -directory name, and the original file contents. In one case, the merge -triggers a rather opaque warning about a “missing file”; in the other, the -merge silently ignores the content changes.</p> -<p>This is a consequence of the way Subversion implements renames and copies. -When Subversion assembles a changeset for committing to the repository, it -comes up with a list of primitive operations that reproduce the change. There -is no primitive that says “this object was moved,” only primitives which say -“this object was deleted” or “this object was added, as a copy of that -object.” When you move a file in Subversion, those two operations are -scheduled. Later, when Subversion goes to merge content changes to the -original file, all it sees is that the file has been deleted; it's completely -unaware that there is a new name for the same file.</p> -<p>This would be fairly easy to remedy by adding a “this object was moved to that -object” primitive to the changeset language, and <a href="http://subversion.tigris.org/issues/show_bug.cgi?id=898">a bug report for just such a -feature</a> was filed in -2002. However, by that time Subversion's repository and changeset formats had -essentially frozen, as Subversion was approaching a 1.0 release and more -important bugs <em>without</em> workarounds were a priority.</p> -<p>There is some work going on in Subversion 1.6 to handle tree conflicts (the -kind of conflicts that come from this kind of structural change) more -sensibly, which will cause the two merges above to generate a Conflict result, -which is not as good as automatically merging it but far better than silently -ignoring changes.</p> -<h2 id="mercurial">Mercurial</h2> -<p><img alt="Mercurial preserves the content -change." src="/media/dev/merging-structural-changes/mercurial-merge-results.png"></p> -<p>Interestingly, there are tools which get this merge scenario right: the -diagram above shows how <a href="http://www.selenic.com/mercurial/">Mercurial</a> handles -the same two tests. Since its changeset language does include an “object -moved” primitive, it's able to take a content change for <code>dir-a/file</code> and -apply it to <code>dir-b/file</code> if appropriate.</p> -<h2 id="git">Git</h2> -<p>Git also gets this scenario right, <em>usually</em>. Unlike Mercurial, Git does not -track file copies or renames in its commits at all, prefering to infer them by -content comparison every time it performs a move-aware operation, such as a -merge.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/merging-structural-changes.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/merging-structural-changes.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/rich-shared-models.html b/.html/dev/rich-shared-models.html deleted file mode 100644 index c4d167c..0000000 --- a/.html/dev/rich-shared-models.html +++ /dev/null @@ -1,187 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Rich Shared Models Must Die - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - rich-shared-models - - </li> - - </ol> - - - - <div id="article"> - <h1 id="rich-shared-models-must-die">Rich Shared Models Must Die</h1> -<p>In a gaming system I once worked on, there was a single class which was -responsible for remembering everything about a user: their name and contact -information, their wagers, their balance, and every other fact about a user -the system cared about. In a system I'm working with now, there's a set of -classes that collaborate to track everything about the domain: prices, -descriptions, custom search properties, and so on.</p> -<p>Both of these are examples of shared, system-wide models.</p> -<p>Shared models are evil.</p> -<p>Shared models <em>must be destroyed</em>.</p> -<p>A software system's model is the set of functions and data types it uses to -decide what to do in response to various events. Models embody the development -team's assumptions and knowledge about the problem space, and usually reflect -the structure of the applications that use them. Not all systems have explicit -models, and it's often hard to draw a line through the code base separating -the code that is the model from the code that is not as every programmer sees -models slightly differently.</p> -<p>With the rise of object-oriented development, explicit models became the focus -of several well-known practices. Many medium-to-large projects are built -“model first,” with the interfaces to that model being sketched out later in -the process. Since the model holds the system's understanding of its task, -this makes sense, and so long as you keep the problem you're actually solving -in mind, it works well. Unfortunately, it's too easy to lose sight of the -problem and push the model as the whole reason for the system around it. This, -in combination with both emotional and technical investment in any existing -system, strongly encourages building <code>new</code> systems around the existing -model pieces even if the relationship between the new system is tenuous at -best.</p> -<ul> -<li>Why do we share them?<ul> -<li>Unmanaged growth<ul> -<li>Adding features to an existing system</li> -<li>Building new systems on top of existing tools</li> -</ul> -</li> -<li>Misguided applications of “simplicity” and “reuse”</li> -<li>Encouraged by distributed object systems (CORBA, EJB, SOAP, COM)</li> -</ul> -</li> -<li>What are the consequences?<ul> -<li>Models end up holding behaviour and data relevant to many applications</li> -<li>Every application using the model has to make the same assumptions</li> -<li>Changing the model usually requires upgrading everyone at the same time</li> -<li>Changes to the model are risky and impact many applications, even if the - changes are only relevant to one application</li> -</ul> -</li> -<li>What should we do instead?<ul> -<li>Narrow, flat interfaces</li> -<li>Each system is responsible for its own modelling needs</li> -<li>Systems share data and protocols, not objects</li> -<li>Libraries are good, if the entire world doesn't need to upgrade at the - same time</li> -</ul> -</li> -</ul> -<p>It's easy to start building a system by figuring out what the various nouns it -cares about are. In the gambling example, one of our nouns was a user (the guy -sitting at a web browser somewhere), who would be able to log in, deposit -money, place a wager, and would have to be notified when the wager was -settled. This is a clear, reasonable entity for describing the goal of placing -bets online, which we could make reasonable assumptions about. It's also a -terrible thing to turn into a class.</p> -<p>The User class in our gambling system was responsible for all of those things; -as a result, every part of the system ended up using a User object somewhere. -Because the User class had many responsibilities, it was subject to frequent -changes; because it was used everywhere, those changes had the capability to -break nearly any part of the overall system. Worse, because so much -functionality was already in one place, it became psychologically easy to add -one more responsibility to its already-bloated interface.</p> -<p>What had been a clean model in the problem space eventually became one of a -handful of “glue” pieces in a <a href="http://www.laputan.org/mud/mud.html#BigBallOfMud">big ball of -mud</a> program. The User -object did not come about through conscious design, but rather through -evolution from a simple system. There was no clear point where User became -“too big”; instead, the vagueness of its role slowly grew until it became the -default behaviour-holder for all things user-specific.</p> -<p>The same problem modeling exercise also points at a better way to design the -same system: it describes a number of capabilities the system needed to be -able to perform, each of which is simpler than “build a gaming website.” Each -of these capabilities (accept or reject logins, process deposits, accept and -settle wagers, and send out notification emails to players) has a much simpler -model and solves a much more constrained of problem. There is no reason the -authentication service needs to share any data except an identity with the -wagering service: one cares about login names, passwords, and authorization -tickets while the other cares about accounting, wins and losses, and posted -odds.</p> -<p>There is a small set of key facts that can be used to correlate all of pieces: -usernames, which uniquely identify a user, can be used to associate data and -behaviour in the login domain with data and behaviour in the accounting and -wagering domain, and with information in a contact management domain. All of -these key facts are flat—they have very little structure and no behaviour, and -can be passed from service to service without dragging along an entire -application's worth of baggage data.</p> -<p>Sharing model classes between many services creates a huge maintenance -bottleneck. Isolating models within the services they support helps encourage -clean separations between services, which in turn makes it much easier to -understand individual services and much easier to maintain the system as a -whole. Kindergarten lied: sharing is <em>wrong</em>.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/rich-shared-models.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/rich-shared-models.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/shutdown-hooks.html b/.html/dev/shutdown-hooks.html deleted file mode 100644 index 7917e81..0000000 --- a/.html/dev/shutdown-hooks.html +++ /dev/null @@ -1,127 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Falsehoods Programmers Believe About Shutdown Hooks - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - shutdown-hooks - - </li> - - </ol> - - - - <div id="article"> - <h1 id="falsehoods-programmers-believe-about-shutdown-hooks">Falsehoods Programmers Believe About Shutdown Hooks</h1> -<p>Shutdown hooks are language features allowing programs to register callbacks to run during the underlying runtime's orderly teardown. For example:</p> -<ul> -<li> -<p>C's <a href="http://man7.org/linux/man-pages/man3/atexit.3.html"><code>atexit</code></a>,</p> -</li> -<li> -<p>Python's <a href="https://docs.python.org/library/atexit.html"><code>atexit</code></a>, which is subtly different,</p> -</li> -<li> -<p>Ruby's <a href="http://www.ruby-doc.org/core-2.1.3/Kernel.html#method-i-at_exit"><code>Kernel.at_exit</code></a>, which is different again,</p> -</li> -<li> -<p>Java's <a href="http://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#addShutdownHook-java.lang.Thread-">Runtime.addShutdownHook</a>, which is yet again different</p> -</li> -</ul> -<p>(There's an example in your favourite language.)</p> -<p>The following beliefs are widespread and incorrect:</p> -<ol> -<li> -<p><strong>Your shutdown hook will run.</strong> Non-exhaustively: the power can go away. The OS may terminate the program immediately because of resource shortages. An administrator or process management tool may send <code>SIGKILL</code> to the process. All of these things, and others, will not run your shutdown hook.</p> -</li> -<li> -<p><strong>Your shutdown hook will run last.</strong> Look at the shapes of the various shutdown hook APIs above: they all allow multiple hooks to be registered in arbitrary orders, and at least one <em>outright requires</em> that hooks run concurrently.</p> -</li> -<li> -<p><strong>Your shutdown hook will not run last.</strong> Sometimes, you win, and objects your hook requires get cleaned up before your hook runs.</p> -</li> -<li> -<p><strong>Your shutdown hook will run to completion.</strong> Some languages run shutdown hooks even when the original termination request came from, for example, the user logging out. Most environments give programs a finite amount of time to wrap up before forcibly terminating them; your shutdown hook may well be mid-run when this occurs.</p> -</li> -<li> -<p><strong>Your shutdown hook will be the only thing running.</strong> In languages that support “daemon” threads, shutdown hooks may start before daemon threads terminate. In languages with concurrent shutdown hooks, other hooks will be in flight at the same time. On POSIX platforms, signals can still arrive during your shutdown hook. (Did you start any child processes? <code>SIGCHLD</code> can still arrive.)</p> -</li> -<li> -<p><strong>You need a shutdown hook.</strong> Closing files, terminating threads, and hanging up network connections are all done automatically by the OS as part of process destruction. The behaviour of the final few writes to a file handle aren't completely deterministic (unflushed data can be lost), but that's true even if a shutdown hook tries to close the file.</p> -</li> -</ol> -<p>Programs that rely on shutdown hooks for correctness should be treated as de-facto incorrect, much like object finalization in garbage-collected languages.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/shutdown-hooks.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/shutdown-hooks.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/stop-building-synchronous-web-containers.html b/.html/dev/stop-building-synchronous-web-containers.html deleted file mode 100644 index 85a1e52..0000000 --- a/.html/dev/stop-building-synchronous-web-containers.html +++ /dev/null @@ -1,135 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Stop Building Synchronous Web Containers - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - stop-building-synchronous-web-containers - - </li> - - </ol> - - - - <div id="article"> - <h1 id="stop-building-synchronous-web-containers">Stop Building Synchronous Web Containers</h1> -<p>Seriously, stop it. It's surreally difficult to build a sane ansynchronous service on top of a synchronous API, but building a synchronous service on top of an asynchronous API is easy.</p> -<ul> -<li> -<p>WSGI: container calls the application as a function, and uses the return - value for the response body. Asynchronous apps generally use a non-WSGI - base (see for example <a href="http://bottlepy.org/docs/dev/async.html">Bottle</a>).</p> -</li> -<li> -<p>Rack: container calls the application as a method, and uses the return - value for the complete response. Asynchronous apps generally use a non-Rack - base (see <a href="https://github.com/rkh/async-rack/issues/5">this Github ticket</a>).</p> -</li> -<li> -<p>Java Servlets: container calls the application as a method, passing a - callback-bearing object as a parameter. The container commits and closes - the response as soon as the application method returns. Asynchronous apps - can use a standard API that operates by <em>re-invoking</em> the servlet method as - needed.</p> -</li> -<li> -<p>What does .Net do?</p> -</li> -</ul> -<p>vs</p> -<ul> -<li>ExpressJS: container calls the application as a function, passing a - callback-bearing object as a parameter. The application is responsible for - indicating that the response is complete.</li> -</ul> -<h2 id="synchronous-web-containers-are-bad-api-design">Synchronous web containers are bad API design</h2> -<ul> -<li> -<p>Make the easy parts easy (this works)</p> -</li> -<li> -<p>Make the hard parts possible (OH SHIT)</p> -</li> -</ul> -<h2 id="writing-synchronous-adapters-for-async-apis-is-easy">Writing synchronous adapters for async APIs is easy</h2> -<pre><code>def adapter(request, response_callback): - synchronous_response = synchronous_entry_point(request) - return response_callback(synchronous_response) -</code></pre> -<p>Going the other way is more or less impossible, which is why websocket -support, HTML5 server-sent event support, and every other async tool for the -web has an awful server interface.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/stop-building-synchronous-web-containers.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/stop-building-synchronous-web-containers.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/trackers-from-first-principles.html b/.html/dev/trackers-from-first-principles.html deleted file mode 100644 index 13ddac4..0000000 --- a/.html/dev/trackers-from-first-principles.html +++ /dev/null @@ -1,297 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Bugs, Tasks, and Tickets from First Principles - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - trackers-from-first-principles - - </li> - - </ol> - - - - <div id="article"> - <h1 id="bugs-tasks-and-tickets-from-first-principles">Bugs, Tasks, and Tickets from First Principles</h1> -<p>Why do we track tasks?</p> -<ul> -<li>To communicate about what should, will, has, and will not be done.<ul> -<li>Consequently, to either build consensus on what to do next or to dictate - it.</li> -</ul> -</li> -<li>To measure and communicate progress.</li> -<li>To preserve information for future use.<ul> -<li>Otherwise we'd just remember it in our heads.</li> -<li>Wishlist tasks are not a bad thing!</li> -</ul> -</li> -</ul> -<p>Bugs/defects are a kind of task but not the only kind. Most teams have a “bug -tracker” that contains a lot more than bugs. Let's not let bugs dictate the -system.</p> -<ul> -<li>Therefore, “steps to reproduce” should not be a required datum.</li> -</ul> -<p>Bugs are an <em>important</em> kind of task.</p> -<p>Tasks can be related to software development artifacts: commits, versions, -builds, releases.</p> -<ul> -<li>A task may only be complete as of certain commits/releases/builds.</li> -<li>A task may only be valid after (or before) certain commits/releases/builds.</li> -</ul> -<p>Communication loosely implies publishing. Tracking doesn't, but may rely on -the publishing of other facts.</p> -<h2 id="core-data">Core Data</h2> -<p>Tasks are only useful if they're actionable. To be actionable, they must be -understood. Understanding requires communication and documentation.</p> -<ul> -<li>A protocol-agnostic <em>name</em>, for easily identifying a task in related - conversations.<ul> -<li>These names need to be <em>short</em> since they're used conversationally. Long - issue names will be shortened by convention whether the tracker supports - it or not.</li> -</ul> -</li> -<li>An actionable <em>description</em> of the task.<ul> -<li>Frequently, a short <em>summary</em> of the task, to ease bulk task - manipulation. Think of the difference between an email subject and an - email body.</li> -</ul> -</li> -<li>A <em>discussion</em>, consisting of <em>remarks</em> or <em>comments</em>, to track the evolving - understanding alongside the task.</li> -</ul> -<p>See <a href="#speciation">speciation</a>, below.</p> -<h2 id="responsibility-and-ownership">Responsibility and Ownership</h2> -<p>Regardless of whether your team operates with a top-down, command-oriented -management structure or with a more self-directed and anarchistic process, for -every task, there is notionally one person currently responsible for ensuring -that the task is completed.</p> -<p>That relationship can change over time; how it does so is probably -team-specific.</p> -<p>There may be other people <em>involved</em> in a task that are not <em>responsible</em> for -a task, in a number of roles. Just because I developed the code for a feature -does not mean I am necessarily responsible for the feature any more, but it -might be useful to have a “developed by” list for the feature's task.</p> -<p>Ways of identifying people:</p> -<ul> -<li>Natural-language names (“Gianna Grady”)</li> -<li>Email addresses</li> -<li>Login names</li> -<li>Distinguished names in some directory</li> -<li>URLs</li> -</ul> -<p>Task responsibility relationships reflect real-world responsibility, and help -communicate it, but do not normally define it.</p> -<h2 id="workflow">Workflow</h2> -<p>“Workflow” describes both the implications of the states a task can be in and -the implications of the transitions between states. Most task trackers are, at -their core, workflow engines of varying sophistication.</p> -<p>Why:</p> -<ul> -<li>Improve shared understanding of how tracked tasks are performed.</li> -<li>Provide clear hand-off points when responsibility shifts.</li> -<li>Provide insight into which tasks need what kinds of attention.</li> -<li>Integration points for other behaviour.</li> -</ul> -<p>States are implicitly time-bounded, and joined to their predecessor and -successor states by transitions.</p> -<p>Task state is decoupled from the real world: the task in a tracker is not the -work it describes.</p> -<p>Elemental states:</p> -<ul> -<li>“Open”: in this state, the task has not yet been completed. Work may or may - not be ongoing.</li> -<li>“Completed”: in this state, all work on a task has been completed.</li> -<li>“Abandoned”: in this state, no further work on a task will be performed, but - the task has not been completed.</li> -</ul> -<p>Most real-world workflows introduce some intermediate states that tie into -process-related handoffs.</p> -<p>For software, I see these divisions, in various combinations, frequently:</p> -<ul> -<li>“Open”:<ul> -<li>“Unverified”: further work needs to be done to decide whether the task - should be completed.</li> -<li>“In Development”: someone is working on the code and asset changes - necessary to complete the task. This occasionally subsumes preliminary - work, too.</li> -<li>“In Testing”: code and asset changes are ostensibly complete, - but need testing to validate that the task has been completed - satisfactorially.</li> -</ul> -</li> -<li>“Completed”:<ul> -<li>“Development Completed”: work (and possibly testing) has been completed - but the task's results are not yet available to external users.</li> -<li>“Released”: work has been completed, and external users can see and use - the results.</li> -</ul> -</li> -<li>“Abandoned”:<ul> -<li>“Cannot Reproduce”: common in bug/defect tasks, to indicate that the - task doesn't contain enough information to render the bug fixable.</li> -<li>“Won't Complete”: the task is well-understood and theoretically - completable, but will not be completed.</li> -<li>“Duplicate”: the task is identical to, or closely related to, some other - task, such that completing either would be equivalent to completing - both.</li> -<li>“Invalid”: the task isn't relevant, is incompletely described, doesn't - make sense, or is otherwise not appropriate work for the team using the - tracker.</li> -</ul> -</li> -</ul> -<p>None of these are universal.</p> -<p>Transitions show how a task moves from state to state.</p> -<ul> -<li>Driven by external factors (dev work leads to tasks being marked completed)<ul> -<li>Explicit transitions: “mark this task as completed”</li> -<li>Implicit transitions: “This commit also completes these tasks”</li> -</ul> -</li> -<li>Drive external factors (tasks marked completed are emailed to testers)</li> -</ul> -<p>States implicitly describe a <em>belief</em> or a <em>desire</em> about the future of the -task, which is a human artifact and may be wrong or overly hopeful. Tasks can -transition to “Completed” or “Abandoned” states when the work hasn't actually -been completed or abandoned, or from “Completed” or “Abandoned” to an “Open” -state to note that the work isn't as done as we thought it was. <em>This is a -feature</em> and trackers that assume every transition is definitely true and -final encourage ugly workarounds like duplicating tickets to reopen them.</p> -<h2 id="speciation">Speciation</h2> -<p>I mentioned above that bugs are a kind of task. The ways in which bugs are -“different” is interesting:</p> -<ul> -<li>Good bugs have a well-defined reproduction case - steps you can follow to - demonstrate and test them.</li> -<li>Good bugs have a well-described expected behaviour.</li> -<li>Good bugs have a well-described actual behaviour.</li> -</ul> -<p>Being able to support this kind of highly detailed speciation of task types -without either bloating the tracker with extension points (JIRA) or -shoehorning all features into every task type (Redmine) is hard, but -necessary.</p> -<p>Supporting structure helps if it leads to more interesting or efficient ways -of using tasks to drive and understand work.</p> -<p>Bugs are not the only “special” kind of task:</p> -<ul> -<li>“Feature” tasks show up frequently, and speciate on having room for - describing specs and scope.</li> -<li>“Support ticket” tasks show up in a few trackers, and speciate dramatically - as they tend to be tasks describing the work of a single incident rather - than tasks describing the work on some shared aspect, so they tend to pick - up fields for relating tickets to the involved parties. (Arguably, incident - tickets have needs so drastically different that you should use a dedicated - incident-management tool, not a task/bug tracker.)</li> -</ul> -<p>Other kinds are possible, and you've probably seen them in the wild.</p> -<p>Ideally, speciation happens to support <em>widespread</em> specialized needs. Bug -repro is a good example; every task whose goal is to fix a defect should -include a clear understanding of the defect, both to allow it to be fixed and -to allow it to be tested. Adding specialized data for bugs supports that by -encouraging clearer, more structured descriptions of the defect (with implicit -“fix this” as the task).</p> -<h2 id="implementation-notes">Implementation notes</h2> -<p>If we reduce task tracking to “record changes to fields and record discussion -comments, on a per task basis,” we can describe the current state of a ticket -using the “most recent” values of each field and the aggregate of all recorded -comments. This can be done ~2 ways:</p> -<ol> -<li>“Centralized” tracking, where each task has a single, total order of - changes. Changes are mediated through a centralized service.</li> -<li>“Decentralized” tracking, where each task has only a partial order over the - history of changes. Changes are mediated by sharing sets of changes, and by - appending “reconciliation” changes to resolve cases where two incomparable - changes modify the same field/s. The most obvious partial order is a - digraph.</li> -</ol> -<p>Centralized tracking is a well-solved problem. Decentralized tracking so far -seems to rely heavily on DSCM tools (Git, Mercurial, Fossil) for resolving -conflicts.</p> -<p>The “work offline” aspect of a distributed tracker is less interesting in as -much as task tracking is a communications tool. Certain kinds of changes -should be published and communicated as early as possible so as to avoid -misunderstandings or duplicated work.</p> -<p>Being able to separate the mechanism of how changes to tasks are recorded from -the policy of which library of tasks is “canonical” is potentially useful as -an editorial tool and for progressive publication to wider audiences as work -progresses.</p> -<p>Issue tracking is considerably more amenable to append-only implementations -than SCM is, even if you dislike history-editing SCM workflows. This suggests -that Git is a poor choice of issue-tracking storage backends...</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/trackers-from-first-principles.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/trackers-from-first-principles.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/twigs.html b/.html/dev/twigs.html deleted file mode 100644 index 66f5e97..0000000 --- a/.html/dev/twigs.html +++ /dev/null @@ -1,112 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Branches and Twigs - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - twigs - - </li> - - </ol> - - - - <div id="article"> - <h1 id="branches-and-twigs">Branches and Twigs</h1> -<h2 id="twigs">Twigs</h2> -<ul> -<li>Relatively short-lived</li> -<li>Share the commit policy of their parent branch</li> -<li>Gain little value from global names</li> -<li>Examples: most “topic branches” are twigs</li> -</ul> -<h2 id="branches">Branches</h2> -<ul> -<li>Relatively long-lived</li> -<li>Correspond to differences in commit policy</li> -<li>Gain lots of value from global names</li> -<li>Examples: git-flow 'master', 'develop', &c; hg 'stable' vs 'default'; - release branches</li> -</ul> -<h2 id="commit-policy">Commit policy</h2> -<ul> -<li>Decisions like “should every commit pass tests?” and “is rewriting or - deleting a commit acceptable?” are, collectively, the policy of a branch</li> -<li>Can be very formal or even tool-enforced, or ad-hoc and fluid</li> -<li>Shared understanding of commit policy helps get everyone's expectations - lined up, easing other SCM-mediated conversations</li> -</ul> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/twigs.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/twigs.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/webapp-versions.html b/.html/dev/webapp-versions.html deleted file mode 100644 index 0a39463..0000000 --- a/.html/dev/webapp-versions.html +++ /dev/null @@ -1,111 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Semver Is Wrong For Web Applications - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - webapp-versions - - </li> - - </ol> - - - - <div id="article"> - <h1 id="semver-is-wrong-for-web-applications">Semver Is Wrong For Web Applications</h1> -<p><a href="http://semver.org">Semantic Versioning</a> (“Semver”) is a great idea, not least -because it's more of a codification of existing practice than a totally novel -approach to versioning. However, I think it's wrong for web applications.</p> -<p>Modern web applications tend to be either totally stagnant - in which case -versioning is irrelevant - or continuously upgraded. Users have no, or very -little, choice as to which version to run: either they run the version currently -on the site, or no version at all. Without the flexibility to choose to run a -specific version, Semver's categorization of versions by what compatibility -guarantees they offer is at best misleading and at worst irrelevant and -insulting.</p> -<p>Web applications must still be <em>versioned</em>; internal users and operators must be -able to trace behavioural changes through to deployments and backwards from -there to <a href="commit-messages">code changes</a>. The continuous and incremental nature -of most web development suggests that a simple, ordered version identifier may -be more appropriate: a <a href="builds">build</a> serial number, or a version <em>date</em>, or -otherwise.</p> -<p>There are <em>parts</em> of web applications that should be semantically versioned: as -the Semver spec says, “Once you identify your public API, you communicate -changes to it with specific increments to your version number,” and this remains -true on the web: whether you choose to support multiple API versions -simultaneously, or to discard all but the latest API version, a semantic version -number can be a helpful communication tool <em>about that API</em>.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/webapp-versions.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/webapp-versions.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/webapps.html b/.html/dev/webapps.html deleted file mode 100644 index aada593..0000000 --- a/.html/dev/webapps.html +++ /dev/null @@ -1,91 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Webapps From The Ground Up - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - webapps - - </li> - - </ol> - - - - <div id="article"> - <h1 id="webapps-from-the-ground-up">Webapps From The Ground Up</h1> -<p>What does a web application do? It sequences side effects and computation. (This should sound familiar: it's what <em>every</em> program does.)</p> -<p>Modern web frameworks do their level best to hide this from you, encouraging code to freely intermix computation, data access, event publishing, logging, responses, <em>asynchronous</em> responses, and the rest. This will damn you to an eternity of debugging.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/webapps.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/webapps.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/whats-wrong-with-jenkins.html b/.html/dev/whats-wrong-with-jenkins.html deleted file mode 100644 index 1b9ab6e..0000000 --- a/.html/dev/whats-wrong-with-jenkins.html +++ /dev/null @@ -1,172 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Something's Rotten in the State of Jenkins - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - whats-wrong-with-jenkins - - </li> - - </ol> - - - - <div id="article"> - <h1 id="somethings-rotten-in-the-state-of-jenkins">Something's Rotten in the State of Jenkins</h1> -<p>Automated, repeatable testing is a fairly widely-accepted cornerstone of -mature software development. Jenkins (and its predecessor, Hudson) has the -unique privilege of being both an early player in the niche and -free-as-in-beer. The blog space is littered with interesting articles about -continuous builds, automated testing, and continuous deployment, all of which -conclude on “how do we make Jenkins do it?”</p> -<p>This is unfortunate, because Jenkins has some serious problems, and I want it -to stop informing the discussion.</p> -<h2 id="theres-a-plugin-for-that">There's A Plugin For That</h2> -<p>Almost everything in the following can be addressed using one or more plugins -from Jenkins' extensive plugin repository. That's good - a build system you -can't extend is kind of screwed - but it also means that the Jenkins team -haven't felt a lot of pressure to address key problems in Jenkins proper.</p> -<p>(Plus, the plugin ecosystem is its own kind of screwed. More on that later.)</p> -<p>To be clear: being able to fix it with plugins does not make Jenkins itself -<em>good</em>. Plugins are a non-response to fundamental problems with Jenkins.</p> -<h2 id="no-granularity">No Granularity</h2> -<p>Jenkins builds are atomic: they either pass en suite, or fail en suite. Jenkins has no built-in support for recording that basic compilation succeeded, unit tests failed, but linting also succeeded.</p> -<p>You can fix this by running more builds, but then you run into problems with -...</p> -<h2 id="no-gating">No Gating</h2> -<p>... the inability to wait for multiple upstream jobs before continuing a -downstream job in a job chain. If your notional build pipeline is</p> -<ol> -<li>Compile, then</li> -<li>Lint and unit test, then</li> -<li>Publish binaries for testers/users</li> -</ol> -<p>then you need to combine the lint and unit test steps into a single build, or -tolerate occasionally publishing between zero and two copies of the same -original source tree.</p> -<h2 id="no-pipeline">No Pipeline</h2> -<p>The above are actually symptomatic of a more fundamental design problem in -Jenkins: there's no build pipeline. Jenkins is a task runner: triggers cause -tasks to run, which can cause further triggers. (Without plugins, Jenkins -can't even ensure that chains of jobs all build the same revisioins from -source control.)</p> -<p>I haven't met many projects whose build process was so simple you could treat -it as a single, pass-fail task, whose results are only interesting if the -whole thing succeeds.</p> -<h2 id="plugin-the-gap">Plugin the Gap</h2> -<p>To build a functional, non-trivial build process on top of Jenkins, you will -inevitably need plugins: plugins for source control, plugins for -notification, plugins for managing build steps, plugins for managing various -language runtimes, you name it.</p> -<p>The plugin ecosystem is run on an entirely volunteer basis, and anyone can -get a new plugin into the official plugin registry. This is good, in as much -as the barrier to entry <em>should</em> be low and people <em>should</em> be encouraged to -scratch itches, but it also means that the plugin registry is a swamp of -sporadically-maintained one-offs with inconsistent interfaces.</p> -<p>(Worse, even some <em>core</em> plugins have serious maintenance deficits: have a -look at how long -<a href="https://issues.jenkins-ci.org/browse/JENKINS-20767">JENKINS-20767</a> was open. -How many Jenkins users use Git?)</p> -<h2 id="the-plugin-api">The Plugin API</h2> -<p>The plugin API also, critically, locks Jenkins into some internal design -problems. The sheer number of plugins, and the sheer number of maintainers, -effectively prevents any major refactoring of Jenkins from making progress. -Breaking poorly-maintained plugins inevitably pisses off the users who were, -quite happily, using whatever they'd cooked up, but with the maintainership -of plugins so spread out and so sporadic, there's no easy way for the Jenkins -team to, for example, break up the <a href="https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/jenkins/model/Jenkins.java">4,000-line <code>Jenkins</code> class</a>.</p> -<h2 id="what-is-to-be-done">What Is To Be Done</h2> -<p>Jenkins is great and I'm glad it exists. Jenkins moved the state of the art -for build servers forward very effectively, and successfully out-competed -more carefully-designed offerings that were not, in fact, better: -<a href="http://continuum.apache.org">Continuum</a> is more or less abandoned, and when -was the last time you saw a -<a href="http://cruisecontrol.sourceforge.net">CruiseControl</a> (caution: SourceForge) -install?</p> -<p>It's interesting to compare the state of usability in, eg., Jenkins, to the -state of usability in some paid-product build systems -(<a href="https://www.atlassian.com/software/bamboo">Bamboo</a> and -<a href="https://www.jetbrains.com/teamcity/">TeamCity</a> for example) on the above -points, as well as looking at the growing number of hosted build systems -(<a href="https://travis-ci.org">TravisCI</a>, <a href="https://magnum-ci.com">MagnumCI</a>) for -ideas. A number of folks have also written insightful musings on what they -want to see in the next CI tool: Susan Potter's -<a href="https://github.com/mbbx6spp/carson">Carson</a> includes an interesting -motivating metaphor (if you're going to use butlers, why not use the whole -butler mileu?) and some good observations on how Jenkins lets us all down, -for example.</p> -<p>I think it's time to put Jenkins to bed and write its successor.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/whats-wrong-with-jenkins.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/whats-wrong-with-jenkins.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/why-scm.html b/.html/dev/why-scm.html deleted file mode 100644 index d278190..0000000 --- a/.html/dev/why-scm.html +++ /dev/null @@ -1,147 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Why we use SCM systems - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - why-scm - - </li> - - </ol> - - - - <div id="article"> - <h1 id="why-we-use-scm-systems">Why we use SCM systems</h1> -<p>I'm watching a newly-minted co-op student dealing with her first encounter -with Git, unhelpfully shepherded by a developer to whom everything below is -already second nature, so deeply that the reasoning is hard to articulate. It -is not going well.</p> -<p>I have the same problem, and it could be me trying to give someone an intro to -Git off the top of my head, but it's not, today. For next time, here are my -thoughts. They have shockingly little to do with Git.</p> -<h2 id="assumptions">Assumptions</h2> -<ul> -<li>You're working on a software project.</li> -<li>You know how to read and write code.</li> -<li>You're human.</li> -<li>You have end users or customers - people other than yourself who care about - your code.</li> -<li>Your project is going to take more than a few minutes to reach end of life.</li> -</ul> -<h2 id="the-safety-net">The safety net</h2> -<p>Having a record of past states and known-good states means that, when (WHEN) -you write some code that doesn't work, and when (WHEN) you're stumped as to -why, you can throw your broken code away and get to a working state again. It -also helps with less-drastic solutions by letting you run comparisons between -your broken code and working code, which helps narrow down whatever problem -you've created for yourself.</p> -<p>(Aside: if you're in a shop that “doesn't use source control,” and for -whatever insane reason you haven't already run screaming, this safety net is a -good reason to use source control independently of the organization as a -whole. Go on, it's easy; modern DSCM tools like Mercurial or Git make -importing “external” trees pretty straightforward. Your future self thanks -you.)</p> -<h2 id="historical-record">Historical record</h2> -<p>Having a record of past, released states means you can go back later and -recover how your project has changed over time. Even if your commit practices -are terrible, when (WHEN) your users complain that something stopped working a -few months ago and they never bothered to mention it until now, you have some -chance of finding out what caused the problem. Better practices around <a href="commit-messages">commit -messages</a> and other workflow-related artifacts improve your -chances of finding out <em>why</em>, too.</p> -<h2 id="consensus">Consensus</h2> -<p>Every SCM system and every release process is designed to help the humans in -the loop agree on what, exactly, the software being released looks like and -whether or not various releasability criteria have been met. It doesn't matter -if you use rolling releases or carefully curate and tag every release after -months of discussion, you still need to be able to point to a specific version -of your project's source code and say “this will be our next release.”</p> -<p>SCM systems can help direct and contextualize that discussion by recording the -way your project has changed during those discussion, whether that's part of -development or a separate post-“freeze” release process.</p> -<h2 id="proposals-and-speculative-development">Proposals and speculative development</h2> -<p>Modern SCM systems (other than a handful of dismal early attempts) also help -you <em>propose</em> and <em>discuss</em> changes. Distributed source control systems make -this particularly easy, but even centralized systems can support workflows -that record speculative development in version control. The ability to discuss -specific changes and diffs, either within a speculative line of development or -between a proposed feature and the mainline code base, is incredibly powerful.</p> -<h2 id="the-bottom-line">The bottom line</h2> -<p>It's about the people, not the tools, stupid. Explaining how Git works to -someone who doesn't have a good grasp on the relationship between source -control tools and long-term, collaborative software development won't help.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/why-scm.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/why-scm.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/devops/_list.html b/.html/devops/_list.html deleted file mode 100644 index b121d4f..0000000 --- a/.html/devops/_list.html +++ /dev/null @@ -1,98 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /devops - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">devops</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /devops</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="continuous-signing">Code Signing on Build Servers</a></li> - - <li><a href="glassfish-and-upstart">Glassfish and Upstart</a></li> - - <li><a href="notes-on-bootstrapping-grimoire-dot-ca">Notes on Bootstrapping This Host</a></li> - - <li><a href="puppet-2.7-to-3.1">Notes on upgrading Puppet from 2.7 to 3.1</a></li> - - <li><a href="autodeploy">Notes towards automating deployment</a></li> - - <li><a href="self-daemonization-sucks">Self-daemonizing code is awful</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/devops">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/devops/autodeploy.html b/.html/devops/autodeploy.html deleted file mode 100644 index 67644a2..0000000 --- a/.html/devops/autodeploy.html +++ /dev/null @@ -1,131 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Notes towards automating deployment - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">devops</a> - - </li> - - <li class="crumb-2 last"> - - autodeploy - - </li> - - </ol> - - - - <div id="article"> - <h1 id="notes-towards-automating-deployment">Notes towards automating deployment</h1> -<p>This is mostly aimed at the hosted-apps folks; deploying packaged software for -end users requires a slightly different approach.</p> -<h2 id="assumptions">Assumptions</h2> -<ol> -<li> -<p>You have one or more <em>services</em> to deploy. (If not, what are you doing -here?)</p> -</li> -<li> -<p>Your services are tracked in <em>source control</em>. (If not, go sort that out, -then come back. No, seriously, <em>now</em>.)</p> -</li> -<li> -<p>You will be deploying your services to one or more <em>environments</em>. An -environment is an abstract thing: think “production,” not -“web01.public.example.com.” (If not, where, exactly, will your service run?)</p> -</li> -<li> -<p>For each service, in each environment, there are one or more <em>servers</em> to -host the service. These servers are functionally identical. (If not, go pave -them and rebuild them using Puppet, Chef, CFengine, or, hell, shell scripts -and duct tape. An environment full of one-offs is the kind of hell I wouldn't -wish on my worst enemy.)</p> -</li> -<li> -<p>For each service, in each environment, there is a canonical series of steps -that produce a “deployed” system.</p> -</li> -</ol> -<hr> -<ol> -<li>Decide what code should be deployed. (This is a version control activity.)</li> -<li>Get the code onto the fucking server.</li> -<li>Decide what configuration values should be deployed. (This is also a - version control activity, though possibly not in the same repositories as - the code.)</li> -<li>Get the configuration onto the fucking server.</li> -<li>Get the code running with the configuration.</li> -<li>Log to fucking syslog.</li> -<li>When the machine reboots, make sure the code comes back running the same - configuration.</li> -</ol> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/devops/autodeploy.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/devops/autodeploy.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/devops/continuous-signing.html b/.html/devops/continuous-signing.html deleted file mode 100644 index 5f61000..0000000 --- a/.html/devops/continuous-signing.html +++ /dev/null @@ -1,93 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Code Signing on Build Servers - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">devops</a> - - </li> - - <li class="crumb-2 last"> - - continuous-signing - - </li> - - </ol> - - - - <div id="article"> - <h1 id="code-signing-on-build-servers">Code Signing on Build Servers</h1> -<p>We sign things so that we can authenticate them later, but authentication is -largely a conscious function. Computers are bad at answering "is this real".</p> -<p>Major signing systems (GPG, jarsigner) require presentation of credentials at -signing time. CI servers don't generally have safe tools for this.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/devops/continuous-signing.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/devops/continuous-signing.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/devops/glassfish-and-upstart.html b/.html/devops/glassfish-and-upstart.html deleted file mode 100644 index 0d03620..0000000 --- a/.html/devops/glassfish-and-upstart.html +++ /dev/null @@ -1,231 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Glassfish and Upstart - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">devops</a> - - </li> - - <li class="crumb-2 last"> - - glassfish-and-upstart - - </li> - - </ol> - - - - <div id="article"> - <h1 id="glassfish-and-upstart">Glassfish and Upstart</h1> -<p><strong>Warning</strong>: the article you're about to read is largely empirical. Take -everything in it in a grain of salt, and <em>verify it yourself</em> before putting -it into production. You have been warned.</p> -<p>The following observations apply to Glassfish 3.1.2.2. Other versions probably -act similarly, but check the docs.</p> -<h2 id="asadmin-create-service"><code>asadmin create-service</code></h2> -<p>Glassfish is capable of emitting SysV init scripts for the DAS, or for any -instance. These init scripts wrap <code>asadmin start-domain</code> and <code>asadmin -start-local-instance</code>. However, the scripts it emits are (justifiably) -minimalist, and it makes some very strong assumptions about the layout of your -system's rc.d trees and about your system's choice of runlevels. The minimal -init scripts avoid any integration with platform “enhancements” (such as -Redhat's <code>/var/lock/subsys</code> mechanism and <code>condrestart</code> convention, or -Debian's <code>start-stop-daemon</code> helpers) in the name of portability, and the -assumptions it makes about runlevels and init layout are becoming -incrementally more fragile as more distributions switch to alternate init -systems with SysV compatiblity layers.</p> -<h2 id="fork-and-expect">Fork and <code>expect</code></h2> -<p>Upstart's process tracking mechanism relies on services following one of three -forking models, so that it can accurately track which children of PID 1 are -associated with which services:</p> -<ul> -<li> -<p>No <code>expect</code> stanza: The service's “main” process is expected not to fork at - all, and to remain running. The process started by upstart is the “main” - process.</p> -</li> -<li> -<p><code>expect fork</code>: The service is expected to call <code>fork()</code> or <code>clone()</code> once. - The process started by upstart itself is not the “main” process, but its - first child process is.</p> -</li> -<li> -<p><code>expect daemon</code>: The service is expected to call <code>fork()</code> or <code>clone()</code> - twice. The first grandchild process of the one started by upstart itself is - the “main” process. This corresponds to classical Unix daemons, which fork - twice to properly dissociate themselves from the launching shell.</p> -</li> -</ul> -<p>Surprisingly, <code>asadmin</code>-launched Glassfish matches <em>none</em> of these models, and -using <code>asadmin start-domain</code> to launch Glassfish from Upstart is not, as far -as I can tell, possible. It's tricky to debug why, since JVM thread creation -floods <code>strace</code> with chaff, but I suspect that either <code>asadmin</code> or Glassfish -itself is forking too many times.</p> -<p>From <a href="https://java.net/projects/glassfish/lists/dev/archive/2012-02/message/9">this mailing list -thread</a>, -though, it appears to be safe to launch Glassfish directly, using <code>java -jar -GLASSFISH_ROOT/modules/glassfish.jar -domain DOMAIN</code>. This fits nicely into -Upstart's non-forking expect mode, but you lose the ability to pass VM -configuration settings to Glassfish during startup. Any memory settings or -Java environment properties you want to pass to Glassfish have to be passed to -the <code>java</code> command manually.</p> -<p>You also lose <code>asadmin</code>'s treatment of Glassfish's working directory. Since -Upstart can configure the working directory, this isn't a big deal.</p> -<h2 id="sigterm-versus-asadmin-stop-domain"><code>SIGTERM</code> versus <code>asadmin stop-domain</code></h2> -<p>Upstart always stops services by sending them a signal. While you can dictate -which signal it uses, you cannot replace signals with another mechanims. -Glassfish shuts down abruptly when it recieves <code>SIGTERM</code> or <code>SIGINT</code>, leaving -some ugly noise in the logs and potentially aborting any transactions and -requests in flight. The Glassfish developers believe this is harmless and that -the server's operation is correct, and that's probably true, but I've not -tested its effect on outward-facing requests or on in-flight operations far -enough to be comfortable with it.</p> -<p>I chose to run a “clean”(er) shutdown using <code>asadmin stop-domain</code>. This fits -nicely in Upstart's <code>pre-stop</code> step, <em>provided you do not use Upstart's -<code>respawn</code> feature</em>. Upstart will correctly notice that Glassfish has already -stopped after <code>pre-stop</code> finishes, but when <code>respawn</code> is enabled Upstart will -treat this as an unexpected termination, switch goals from <code>stop</code> to -<code>respawn</code>, and restart Glassfish.</p> -<p>(The Upstart documentation claims that <code>respawn</code> does not apply if the tracked -process exits during <code>pre-stop</code>. This may be true in newer versions of -Upstart, but the version used in Ubuntu 12.04 does restart Glassfish if it -stops during <code>pre-stop</code>.)</p> -<p>Yes, this does make it impossible to stop Glassfish, ever, unless you set a -respawn limit.</p> -<p>Fortunately, you don't actually want to use <code>respawn</code> to manage availability. -The <code>respawn</code> mode cripples your ability to manage the service “out of band” -by forcing Upstart to restart it as a daemon every time it stops for any -reason. This means you cannot stop a server with <code>SIGTERM</code> or <code>SIGKILL</code>; it'll -immediately start again.</p> -<h2 id="initctl-reload"><code>initctl reload</code></h2> -<p>It sends <code>SIGHUP</code>. This does not reload Glassfish's configuration. Deal with -it; use <code>initctl restart</code> or <code>asadmin restart-domain</code> instead. Most of -Glassfish's configuration can be changed on the fly with <code>asadmin set</code> or -other commands anyways, so this is not a big limitation.</p> -<h2 id="instances">Instances</h2> -<p>Upstart supports “instances” of a service. This slots nicely into Glassfish's -ability to host multiple domains and instances on the same physical hardware. -I ended up with a generic <code>glassfish-domain.conf</code> Upstart configuration:</p> -<pre><code>description "Glassfish DAS" -console log - -instance $DOMAIN - -setuid glassfish -setgid glassfish -umask 0022 -chdir /opt/glassfish3 - -exec /usr/bin/java -jar /opt/glassfish3/glassfish/modules/glassfish.jar -domain "${DOMAIN}" - -pre-stop exec /opt/glassfish3/bin/asadmin stop-domain "${DOMAIN}" -</code></pre> -<p>Combined with a per-domain wrapper:</p> -<pre><code>description "Glassfish 'example' domain" -console log - -# Consider using runlevels here. -start on started networking -stop on deconfiguring-networking - -pre-start script - start glassfish-domain DOMAIN=example -end script - -post-stop script - stop glassfish-domain DOMAIN=example -end script -</code></pre> -<h2 id="possible-refinements">Possible refinements</h2> -<ul> -<li> -<p>Pull system properties and VM flags from the domain's own <code>domain.xml</code> - correctly. It might be possible to abuse the (undocumented, unsupported, but - helpful) <code>--_dry-run</code> argument from <code>asadmin start-domain</code> for this, or it - might be necessary to parse <code>domain.xml</code> manually, or it may be possible to - exploit parts of Glassfish itself for this.</p> -</li> -<li> -<p>The <code>asadmin</code> cwd is actually the domain's <code>config</code> dir, not the Glassfish - installation root.</p> -</li> -<li> -<p>Something something something password files.</p> -</li> -<li> -<p>Syslog and logrotate integration would be useful. The configurations above - spew Glassfish's startup output and stdout to - <code>/var/log/upstart/glassfish-domain-FOO.log</code>, which may not be rotated by - default.</p> -</li> -</ul> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/devops/glassfish-and-upstart.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/devops/glassfish-and-upstart.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/devops/index.html b/.html/devops/index.html deleted file mode 100644 index b121d4f..0000000 --- a/.html/devops/index.html +++ /dev/null @@ -1,98 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /devops - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">devops</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /devops</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="continuous-signing">Code Signing on Build Servers</a></li> - - <li><a href="glassfish-and-upstart">Glassfish and Upstart</a></li> - - <li><a href="notes-on-bootstrapping-grimoire-dot-ca">Notes on Bootstrapping This Host</a></li> - - <li><a href="puppet-2.7-to-3.1">Notes on upgrading Puppet from 2.7 to 3.1</a></li> - - <li><a href="autodeploy">Notes towards automating deployment</a></li> - - <li><a href="self-daemonization-sucks">Self-daemonizing code is awful</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/devops">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/devops/notes-on-bootstrapping-grimoire-dot-ca.html b/.html/devops/notes-on-bootstrapping-grimoire-dot-ca.html deleted file mode 100644 index e5a1b47..0000000 --- a/.html/devops/notes-on-bootstrapping-grimoire-dot-ca.html +++ /dev/null @@ -1,166 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Notes on Bootstrapping This Host - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">devops</a> - - </li> - - <li class="crumb-2 last"> - - notes-on-bootstrapping-grimoire-dot-ca - - </li> - - </ol> - - - - <div id="article"> - <h1 id="notes-on-bootstrapping-this-host">Notes on Bootstrapping This Host</h1> -<p>Presented without comment:</p> -<ul> -<li> -<p>Package updates:</p> -<pre><code>apt-get update -apt-get upgrade -</code></pre> -</li> -<li> -<p>Install Git:</p> -<pre><code>apt-get install git -</code></pre> -</li> -<li> -<p>Set hostname:</p> -<pre><code>echo 'grimoire' > /etc/hostname -sed -i -e $'s,ubuntu,grimoire.ca\tgrimoire,' /etc/hosts -poweroff -</code></pre> -<p>To verify:</p> -<pre><code>hostname -f # => grimoire.ca -hostname # => grimoire -</code></pre> -</li> -<li> -<p>Add <code>owen</code> user:</p> -<pre><code>adduser owen -adduser owen sudo -</code></pre> -<p>To verify:</p> -<pre><code>id owen # => uid=1000(owen) gid=1000(owen) groups=1000(owen),27(sudo) -</code></pre> -</li> -<li> -<p>Install Puppetlabs Repos:</p> -<pre><code>wget https://apt.puppetlabs.com/puppetlabs-release-pc1-trusty.deb -dpkg -i puppetlabs-release-pc1-trusty.deb -apt-get update -</code></pre> -</li> -<li> -<p>Install Puppet server:</p> -<pre><code>apt-get install puppetserver -sed -i \ - -e '/^JAVA_ARGS=/ s,2g,512m,g' \ - -e '/^JAVA_ARGS=/ s, -XX:MaxPermSize=256m,,' \ - /etc/default/puppetserver -service puppetserver start -</code></pre> -</li> -<li> -<p>Test Puppet agent:</p> -<pre><code>/opt/puppetlabs/bin/puppet agent --test --server grimoire.ca -</code></pre> -<p>This should output the following:</p> -<pre><code>Info: Retrieving pluginfacts -Info: Retrieving plugin -Info: Caching catalog for grimoire.ca -Info: Applying configuration version '1446415926' -Info: Creating state file /opt/puppetlabs/puppet/cache/state/state.yaml -Notice: Applied catalog in 0.01 seconds -</code></pre> -</li> -<li> -<p>Install environment:</p> -<pre><code>git init --bare /root/puppet.git -# From workstation, `git push root@grimoire.ca:puppet.git master` to populate the repo -rm -rf /etc/puppetlabs/code/environments/production -git clone /root/puppet.git /etc/puppetlabs/code/environments/production -</code></pre> -</li> -<li> -<p>Bootstrap puppet:</p> -<pre><code>/opt/puppetlabs/bin/puppet agent --test --server grimoire.ca -</code></pre> -</li> -</ul> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/devops/notes-on-bootstrapping-grimoire-dot-ca.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/devops/notes-on-bootstrapping-grimoire-dot-ca.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/devops/puppet-2.7-to-3.1.html b/.html/devops/puppet-2.7-to-3.1.html deleted file mode 100644 index ca53067..0000000 --- a/.html/devops/puppet-2.7-to-3.1.html +++ /dev/null @@ -1,147 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Notes on upgrading Puppet from 2.7 to 3.1 - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">devops</a> - - </li> - - <li class="crumb-2 last"> - - puppet-2.7-to-3.1 - - </li> - - </ol> - - - - <div id="article"> - <h1 id="notes-on-upgrading-puppet-from-27-to-31">Notes on upgrading Puppet from 2.7 to 3.1</h1> -<h2 id="bad">Bad</h2> -<ul> -<li> -<p>As usual, you have to upgrade the puppet master first. 2.7 agents can speak - to 3.1 masters just fine, but 3.1 agents cannot speak to 2.7 masters.</p> -</li> -<li> -<p>I tried to upgrade the Puppet master using both <code>puppet agent</code> (failed when - package upgrades shut down the puppet master) and <code>puppet apply</code> (failed for - Ubuntu-specific reasons outlined below)</p> -</li> -<li> -<p><a href="https://projects.puppetlabs.com/issues/19308">This bug</a>.</p> -</li> -<li> -<p>You more or less can't upgrade Puppet using Puppet.</p> -</li> -</ul> -<h2 id="good">Good</h2> -<ul> -<li> -<p>My 2.7 manifests worked perfectly under 3.1.</p> -</li> -<li> -<p>Puppet's CA and SSL certs survived intact and required no maintenance after - the upgrade.</p> -</li> -<li> -<p>The Hiera integration into class parameters works as advertised and really - does help a lot.</p> -</li> -<li> -<p>Once I figured out how to execute it, the upgrade was pretty smooth.</p> -</li> -<li> -<p>No Ruby upgrade!</p> -</li> -<li> -<p>Testing the upgrade in a VM sandbox meant being able to fuck up safely. - <a href="http://www.vagrantup.com">Vagrant</a> is super awesome.</p> -</li> -</ul> -<h2 id="package-management-sucks">Package Management Sucks</h2> -<p>Asking Puppet to upgrade Puppet went wrong on Ubuntu because of the way Puppet -is packaged: there are three (ish) Puppet packages, and Puppet's resource -evaluation bits try to upgrade and install one package at a time. Upgrading -only “puppetmaster” upgraded “puppet-common” but not “puppet,” causing Apt to -remove “puppet”; upgrading only “puppet” similarly upgraded “puppet-copmmon” -but not “puppetmaster,” causing Apt to remove “puppetmaster.”</p> -<p>The Puppet aptitude provider (which I use instead of apt-get) for Package -resources also doesn't know how to tell aptitude what to do with config files -during upgrades. This prevented Puppet from being able to upgrade pacakges -even when running standalone (via <code>puppet apply</code>).</p> -<p>Finally, something about the switchover from Canonical's Puppet .debs to -Puppetlabs' .debs caused aptitude to consider all three packages “broken” -after a manual upgrade ('aptitude upgrade puppet puppetmaster'). Upgrading the -packages a second time corrected it; this is the path I eventually took with -my production puppetmaster and nodes.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/devops/puppet-2.7-to-3.1.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/devops/puppet-2.7-to-3.1.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/devops/self-daemonization-sucks.html b/.html/devops/self-daemonization-sucks.html deleted file mode 100644 index 14e2c01..0000000 --- a/.html/devops/self-daemonization-sucks.html +++ /dev/null @@ -1,162 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Self-daemonizing code is awful - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">devops</a> - - </li> - - <li class="crumb-2 last"> - - self-daemonization-sucks - - </li> - - </ol> - - - - <div id="article"> - <h1 id="self-daemonizing-code-is-awful">Self-daemonizing code is awful</h1> -<p>The classical UNIX approach to services is to implement them as “daemons,” -programs that run without a terminal attached and provide some service. The -key feature of a classical daemon is that, when started, it carefully -detaches itself from its initial environment and terminal, then continues -running in the background.</p> -<p>This is awful and I'm glad modern init replacements discourage it.</p> -<h2 id="process-tracking">Process Tracking</h2> -<p>Daemons don't exist in a vacuum. Administrators and owners need to be able to -start and stop daemons reliably, and check their status. The classic -self-daemonization approach makes this impossible.</p> -<p>Traditionally, daemons run as children of <code>init</code> (pid 1), even if they start -out as children of some terminal or startup process. Posix only provides -deterministic APIs for processes to manage their children and their immediate -parents; the classic daemonisation protocol hands the newly-started daemon -process off from its original parent process, which knows how to start and -stop it, to an unsuspecting <code>init</code>, which has no idea how this specific -daemon is special.</p> -<p>The standard workaround has daemons write their own PIDs to a file, but a -file is “dead” data: it's not automatically updated if the daemon dies, and -can linger long enough to contain the PID of some later, unrelated program. -PID file validity checks generally suffer from subtle (or, sometimes, quite -gross) race conditions.</p> -<h2 id="complexity">Complexity</h2> -<p>The actual <em>code</em> to correctly daemonize a process is surprisingly complex, -given the individual interfaces' relative simplicity:</p> -<ul> -<li> -<p>The daemon must start its own process group</p> -</li> -<li> -<p>The daemon must detach from its controlling terminal</p> -</li> -<li> -<p>The daemon should close (and may reopen) file handles inherited from its - parent process (generally, a shell)</p> -</li> -<li> -<p>The daemon should ensure its working directory is predictable and - controllable</p> -</li> -<li> -<p>The daemon should ensure its umask is predictable and controllable</p> -</li> -<li> -<p>If the daemon uses privileged resources (such as low-numbered ports), it - should carefully manage its effective, real, and session UID and GIDs</p> -</li> -<li> -<p>Daemons must ensure that all of the above steps happen in signal-safe ways, - so that a daemon can be shut down sanely even if it's still starting up</p> -</li> -</ul> -<p>See <a href="http://www.freedesktop.org/software/systemd/man/daemon.html">this list</a> -for a longer version. It's worse than you think.</p> -<p>All of this gets even more complicated if the daemon has its own child -processes, a pattern common to network services. Naturally, a lot of daemons -in the real world get some of these steps wrong.</p> -<h2 id="the-future">The Future</h2> -<p><a href="http://supervisord.org">Supervisord</a>, -<a href="http://ddollar.github.io/foreman/">Foreman</a>, -<a href="http://upstart.ubuntu.com">Upstart</a>, -<a href="https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/launchctl.1.html">Launchd</a>, -<a href="http://www.freedesktop.org/wiki/Software/systemd/">systemd</a>, and <a href="http://cr.yp.to/daemontools.html">daemontools</a> all -encourage services <em>not</em> to self-daemonize by providing a sane system for -starting the daemon with the right parent process and the right environment -in the first place.</p> -<p>This is a great application of -<a href="http://c2.com/cgi/wiki?DontRepeatYourself">DRY</a>, as the daemon management -code only needs to be written once (in the daemon-managing daemon) rather -than many times over (in each individual daemon). It also makes daemon -execution more predictable, since daemons “in production” behave more like -they do when run attached to a developer's console during debugging or -development.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/devops/self-daemonization-sucks.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/devops/self-daemonization-sucks.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/email.html b/.html/email.html deleted file mode 100644 index 8f64a63..0000000 --- a/.html/email.html +++ /dev/null @@ -1,98 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Why I Didn't Answer Your Email - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="./">index</a> - - </li> - - <li class="crumb-1 last"> - - email - - </li> - - </ol> - - - - <div id="article"> - <h1 id="why-i-didnt-answer-your-email">Why I Didn't Answer Your Email</h1> -<p><img alt="An email appears! Aww, man. Will I think differently after reading it? If -yes, then read immediately. If no, then will I act differently after reading -it? If yes, then read immediately. If no, then is it from someone funny? If -yes, then read immediately. If no, UNREAD FOREVER." src="/media/email/flowchart.png"></p> -<p>I get a lot of email, often while I'm in <a href="http://blog.ninlabs.com/2013/01/programmer-interrupted/">the middle of something -thought-intensive</a>. -Managing interruptions and my attention means I have to triage emails based on -only two things: who sent them, and what they wrote in the subject line. If I -didn't answer yours, it's probably not personal: I probably glanced at it when -it arrived and mentally put it on the “later” pile instead of the “now” pile, -and “later” can be a very long time indeed.</p> -<p>If it was actually important that I read and respond to your email, and I -couldn't tell that from the subject, what the hell is wrong with your writing? -If you can live without my reply, well, you're smart: work something out -without me. I'll probably think it's cool.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/email.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/email.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/ethics/_list.html b/.html/ethics/_list.html deleted file mode 100644 index ff9ddb3..0000000 --- a/.html/ethics/_list.html +++ /dev/null @@ -1,92 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /ethics - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">ethics</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /ethics</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="lg-smart-tv">LG Smart TVs are dumb</a></li> - - <li><a href="linkedin-intro">LinkedIn Intro is Unethical Software</a></li> - - <li><a href="musings">Undirected Musings about Ethics</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/ethics">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/ethics/index.html b/.html/ethics/index.html deleted file mode 100644 index ff9ddb3..0000000 --- a/.html/ethics/index.html +++ /dev/null @@ -1,92 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /ethics - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">ethics</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /ethics</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="lg-smart-tv">LG Smart TVs are dumb</a></li> - - <li><a href="linkedin-intro">LinkedIn Intro is Unethical Software</a></li> - - <li><a href="musings">Undirected Musings about Ethics</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/ethics">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/ethics/lg-smart-tv.html b/.html/ethics/lg-smart-tv.html deleted file mode 100644 index 5f565b4..0000000 --- a/.html/ethics/lg-smart-tv.html +++ /dev/null @@ -1,180 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - LG Smart TVs are dumb - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">ethics</a> - - </li> - - <li class="crumb-2 last"> - - lg-smart-tv - - </li> - - </ol> - - - - <div id="article"> - <h1 id="lg-smart-tvs-are-dumb">LG Smart TVs are dumb</h1> -<p>(Or, corporate entitlement run amok.)</p> -<p><a href="http://doctorbeet.blogspot.co.uk/2013/11/lg-smart-tvs-logging-usb-fil -enames-and.html">According to a UK -blogger</a>, LG Smart TVs not only offer “smart” features, but also -track your viewing habits <em>extremely</em> closely by submitting events back to LG -and to LG's advertising affiliates.</p> -<p>Under his diagnosis, the TV sends an event to LG that identifies the specific TV</p> -<ul> -<li> -<p>every time the viewer changes channels (containing the name of the channel being watched)</p> -</li> -<li> -<p>whenever a USB device is inserted (containing the names of files stored on the USB stick)</p> -</li> -</ul> -<p>The page comments additionally suggest that the TV sends back information -whenever the menu is opened, as well.</p> -<p>This information is used to provide targeted advertising, likely to offset -the operational cost of the TV's “intelligent” features. Consumer protections -around personal data and tracking have traditionally been very weak, so it's -not entirely surprising that LG would choose to extract revenue this way -instead of raising the price of the product to cover the operational costs and instead of offering the intelligent features as a subscription service, but this is extremely disappointing.</p> -<h2 id="how-is-this-harmful">How is this harmful?</h2> -<p>LG uses this information to sell <a href="http://us.lgsmartad.com/main/main.lge">targeted -advertising</a>, extracting value for -itself out from the presence of other peoples' eyeballs. We've collectively -chosen to accept that content producers -- website owners, for example -- can -sell advertising as a way to augment their income from the content they -produce. However, LG is not a content producer; while you can choose to leave -a website that uses invasive ad tracking, LG's position is more analogous to -that of the web browser itself: they get to watch the customer's habits no matter what they choose to watch.</p> -<p>There is a material difference between advertising targeted by time slot and -by the content distributors (television networks) on their own behalf, which -has been part of television nearly from its inception, and the kind of -personally-invasive and cross-channel targeted advertising LG is engaging in. -LG's ability to correlate viewing habits across every channel and across -non-public media the user watches places them in a position where they may -well derive more information about the people watching TV than those peoples' -own spouses or parents would be trusted with. We've already seen this kind of -comprehensive statistical modelling go wrong; <a href="http://www.forbes.com/sites/kashmirhill/2012/02/16/how-target-figured-ou - t-a-teen-girl-was-pregnant-before-her-father-did/">Target's advertising folks -landed in hot water last -year</a> after their -purchase-habit-derived models revealed information about a customer that she -didn't even have about herself.</p> -<p>LG is also taking zero care to ensure that the private information it's -silently extracting from viewers is not diseminated further. The TV sends -viewing information - channel names, file names from USB sticks, and so on - -over the internet in plain text, allowing anyone on the network path between -the TV and LG to intercept it and use it for their own ends. This kind of -information is incredibly useful for targeted fraud, and I'm sure the NSA is -thrilled to have such a useful source of personally-identifying and -habit-revealing data available for free, too.</p> -<h2 id="icing-on-the-cake">Icing on the cake</h2> -<p>The TV's settings menu contains an item entitled “Collection of watching -info” which can be turned to “On” (the default, even if the customer rejects -the end-user license agreement on the television and disables the -“intelligent” features) or “Off.” It would be reasonable to expect that this -option would stop the TV from communicating viewing habits to the internet; -however, the setting appears to do very little. The article shows packet -captures of the TV submitting viewing information to LG with the setting in -either position.</p> -<p>The setting also has no help text to guide customers to understanding what it -<em>actually</em> does or to clarify expectations around it.</p> -<h2 id="lgs-stance-is-morally-indefensible">LG's stance is morally indefensible</h2> -<p>From the blog post, LG's representative claims that viewers “agree” to this -monitoring when they accept the TV's end-user license agreement, and that -it's up to the retailer to inform the user of the contents of the license -agreement. However:</p> -<ol> -<li> -<p>LG does not ensure that retailers tell potential buyers about the end-user license conditions; they claim it's up to the retailer's individual discretion.</p> -</li> -<li> -<p>There's no incentive for retailers to tell customers about the license agreement, as the agreement is between LG and the customer, not between the retailer and the customer. Stopping each sale to talk about license terms is likely to reduce the number of sales, too.</p> -</li> -<li> -<p>It would be impractical for retailers to inform customers of every license for every product they sell, as there are unique licenses for nearly every piece of software and for most computer-enabled products (i.e., most of them). Retailers do not habitually employ contract lawyers to accurately guide customers through the license agreements.</p> -</li> -<li> -<p>LG's own packaging makes the license agreement effectively unviewable without committing the money to buy a TV. It's only presented on the TV itself after it's installed and turned on (which often voids the customer's ability to return it to the retailer), and in retailer-specific parts of LG's own website, which isn't practically available while the customer is standing in a shop considering which TV to buy.</p> -</li> -</ol> -<p>It is not reasonable to expect customers to assume their TV will track -viewing habits publicly. This is not a behaviour that TVs have had over their -multi-decade existence, and it's disingenuous for LG to act like the customer -“should have known” in any sense that the LG TV acts in this way.</p> -<p>LG is hiding behind the modern culture of unfair post-sale contracts to -impose a novel, deeply-invasive program of customer monitoring for their own -benefit, relying on corporate law to protect themselves from consumer -reprisals. This cannot be allowed to continue; vote with your dollars.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/ethics/lg-smart-tv.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/ethics/lg-smart-tv.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/ethics/linkedin-intro.html b/.html/ethics/linkedin-intro.html deleted file mode 100644 index be73d06..0000000 --- a/.html/ethics/linkedin-intro.html +++ /dev/null @@ -1,251 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - LinkedIn Intro is Unethical Software - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">ethics</a> - - </li> - - <li class="crumb-2 last"> - - linkedin-intro - - </li> - - </ol> - - - - <div id="article"> - <h1 id="linkedin-intro-is-unethical-software">LinkedIn Intro is Unethical Software</h1> -<p><a href="https://intro.linkedin.com">LinkedIn Intro</a> is a mail filtering service -provided by LinkedIn that inserts LinkedIn relationship data into the user's -incoming and outgoing mail. This allows, for example, LinkedIn to decorate -incoming mail with a toolbar linking to the sender's LinkedIn account, and -automatically injects a short “signature” of your LinkedIn profile into -outgoing mail.</p> -<p>These are useful features, and the resulting interaction is quite smooth. -However, the implementation has deep, unsolvable ethical problems.</p> -<p>LinkedIn Intro reconfigures the user's mobile device, replacing their mail -accounts with proxy mail accounts that use LinkedIn's incoming and outgoing -mail servers. All of LinkedIn's user-facing features are implemented using -HTML and JavaScript injected directly into the email message.</p> -<h2 id="password-concerns">Password Concerns</h2> -<p>LinkedIn Intro's proxy mail server must be able to log into the user's real -incoming mail server to retrieve mail, and often must log into the user's real -outgoing mail server to deliver mail with correct SPF or DKIM validation. This -implies that LinkedIn Intro must know the user's email credentials, which it -acquires from their mobile device. Since this is a “use” of a password, not -merely a “validation” of an incoming password, the password must be available -<em>to LinkedIn</em> as plain text. There are two serious problems with this that -are directly LinkedIn's responsibilty, and a third that's indirect but -important. (Some email providers - notably Google - support non-password, -revokable authentication mechanisms for exactly this sort of use. It's not -clear whether LinkedIn Intro uses these safer mechanisms, but it doesn't -materially change my point.)</p> -<p>LinkedIn has a somewhat unhappy security history. In 2012, they had a -<a href="http://www.nytimes.com/2012/06/11/technology/linkedin-breach-exposes-light-security-even-at-data-companies.html">security -breach</a> -that exposed part of their authentication database to the internet. While they -have very likely tightened up safeguards in response, it's unclear whether -those include a cultural change towards more secure practices. Certainly, it -will take longer than the year that's passed for them to build better trust -from the technical community.</p> -<p>Worse, the breach revealed that LinkedIn was actively disregarding known -problems with password storage for authentication. <a href="http://cm.bell-labs.com/cm/cs/who/dmr/passwd.ps">Since at least the late -70's</a>, the security community -has been broadly aware of weaknesses of unsalted hash-based password -obfuscation. More recently, <a href="http://www.win.tue.nl/cccc/sha-1-challenge.html">it's become -clear</a> that CPU-optimized -hash algorithms (including MD5 and both SHA-1 and SHA-2) are weak protection -against massively parallel password cracking — cracking that's quite cheap -using modern GPUs. Algorithms like -<a href="http://codahale.com/how-to-safely-store-a-password/">bcrypt</a> which address -this specific weakness have been available since the late 90's. LinkedIn's -leaked password database was stored using unsalted SHA-1 digests, suggesting -either a lack of research or a lack of understanding of the security -implications of their password system.</p> -<p>Rebuilding trust after this kind of public shaming should have involved a -major, visible shift in the company's culture. There's easy marketing among -techies — a major portion of LinkedIn's audience, even now — to be done by -showing how on the ball you can be about protecting their data; none of this -marketing has appeared. The impact of raising the priority of security issues -throughout product development should be visible from the outside, as risky -features get pushed aside to address more fundamental security issues; no such -shift in priorities has been visible. It is reasonable, observing LinkedIn's -behaviour in the last year, to conclude that LinkedIn, as a company, still -treats data security as an easy problem to be solved with as little effort as -possible. This is not a good basis on which to ask users to hand over their -email passwords.</p> -<p>While the security community has been making real efforts to educate users to -use a unique password for each service they use, the sad reality is that most -users still use the same password for everything. As LinkedIn Intro must -necessarily store <em>plain text</em> passwords, it will be a very attractive target -for future break-ins, for employee malfeasance, and for United States court -orders.</p> -<h2 id="what-gets-seen">What Gets Seen</h2> -<p>LinkedIn Intro is not selective. Every email that passes through an -Intro-enabled email account is visible, entirely, to LinkedIn. The fact that -the email occurred is fodder for their recommendation engine and for any other -analysis they care to run. The contents may be retained indefinitely, outside -of either the sender's or the recipients' control. LinkedIn is in a position -to claim that Intro users have given it <em>permission</em> to be intrusive into -their email in this way.</p> -<p>Very few people use a dedicated email account for “corporate networking” and -recruiting activities. A CEO (LinkedIn's own example) recieves mail pertaining -to many sensitive aspects of a corporation's running: lawsuit notices, gossip -among the exec team, planning emails discussing the future of the company, -financials, email related to external partnerships at the C*O level, and many, -many other things. LinkedIn's real userbase, recruiters and work-seeking -people, often use the same email account for LinkedIn and for unrelated -private activities. LinkedIn <em>has no business</em> reading these emails or even -knowing of their existence, but Intro provides no way to restrict what -LinkedIn sees.</p> -<p>Users in heavily-regulated industries, such as health care or finance, may be -exposing their whole organization to government interventions by using Intro, -as LinkedIn is not known to be HIPAA, SOX, or PCI compliant.</p> -<p>The resulting “who mailed what to whom” database is hugely valuable. I expect -LinkedIn to be banking on this; such a corpus of conversational data would -greatly help them develop new features targetting specific groups of users, -and could improve the overall effectiveness of their recommendation engine. -However, it's also valuable to others; as above, this information would be a -gold mine for marketers, a target for break-ins, and, worryingly, <em>immensely</em> -useful to the United States' intelligence apparatus (who can obtain court -orders preventing LinkedIn from discussing their requests, to boot).</p> -<p>(LinkedIn's recommendation engine also has issues; it's notorious for -<a href="http://community.linkedin.com/questions/31650/linkedin-sent-an-ex-girlfriend-a-request-to-someon.html">recommending people to their own -ex-partners</a> -and to people actively suing one another. Giving it more data to work with -makes this more likely, especially when the data is largely unrelated to -professional concerns..)</p> -<p>LinkedIn Intro's injected HTML is also suspect by default. Tracking email open -rates is standard practice for email marketing, but Intro allows <em>LinkedIn</em> to -track the open rate of emails <em>you send</em> and of emails <em>you recieve</em>, -regardless of whether those emails pertain to LinkedIn's primary business or -not.</p> -<h2 id="user-education">User Education</h2> -<p>All of the risks outlined above are manageable. With proper information, the -end user can make an informed decision as to whether</p> -<ul> -<li>to ignore Intro at all, or</li> -<li>to use Intro with a dedicated “LinkedIn Only” email account, or</li> -<li>to use Intro with everything</li> -</ul> -<p>LinkedIn's own marketing materials outline <em>absolutely none</em> of these risks. -They're designed, as most app landing materials are, to make the path to -downloading and configuring Intro as smooth and unthreatening as possible: the -option to install the application is presented before the page describes what -the app <em>does</em>, and it never describes how the app <em>works</em> — that information -is never stated outright, not even in Intro's own -<a href="https://intro.linkedin.com/micro/faq">FAQ</a>. Witholding the risks from users -vastly increases the chances of a user making a decision they aren't -comfortable with, or that increases their own risk of social or legal problems -down the road.</p> -<h2 id="linkedins-response">LinkedIn's Response</h2> -<p>Shortly after Intro's first round of public mockery, a LinkedIn employee -<a href="http://blog.linkedin.com/2013/10/26/the-facts-about-linkedin-intro/">posted a -response</a> -to some of the security concerns. The post is interesting, and I recommend you -read it.</p> -<p>The key point about the response is that it underscores how secure Intro is -<em>for LinkedIn</em>. It does absolutely nothing to discuss how LinkedIn is curating -its users' security needs. In particular:</p> -<blockquote> -<p>We isolated Intro in a separate network segment and implemented a -tight security perimeter across trust boundaries.</p> -</blockquote> -<p>A breach in LinkedIn proper may not imply a breach in LinkedIn Intro, and vice -versa, but there must be at least some data passing back and forth for Intro -to operate. The nature and structure of the security mechanisms that permit -the “right” kind of data are not elaborated on; it's impossible to decide how -well they actually insulate Intro from LinkedIn. Furthermore, a breach in -LinkedIn Intro is still incredibly damaging even if it doesn't span LinkedIn -itself.</p> -<blockquote> -<p>Our internal team of experienced testers also penetration-tested the -final implementation, and we worked closely with the Intro team to -make sure identified vulnerabilities were addressed.</p> -</blockquote> -<p>This doesn't address the serious concerns with LinkedIn Intro's <em>intended</em> -use; it also doesn't do much to help users understand how thorough the testing -was or to understand who vetted the results.</p> -<h2 id="the-bottom-line">The Bottom Line</h2> -<p><em>If</em> LinkedIn Intro works as built, and <em>if</em> their security safeguards are as -effective as they claim and hope, then Intro exposes its users to much greater -risk of password compromise and helps them expose themselves to surveillence, -both government and private. If either of those conditions does not hold, it's -worse.</p> -<p>The software industry is young, and immature, and wealthy. There is no ethics -body to complain to; had the developers of Intro said “no,” they would very -likely have been replaced by another round of developers who would help -LinkedIn violate their users' privacy. That does not excuse LinkedIn; their -product is vile, and must not be tolerated in the market.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/ethics/linkedin-intro.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/ethics/linkedin-intro.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/ethics/musings.html b/.html/ethics/musings.html deleted file mode 100644 index 4090d46..0000000 --- a/.html/ethics/musings.html +++ /dev/null @@ -1,146 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Undirected Musings about Ethics - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">ethics</a> - - </li> - - <li class="crumb-2 last"> - - musings - - </li> - - </ol> - - - - <div id="article"> - <h1 id="undirected-musings-about-ethics">Undirected Musings about Ethics</h1> -<h2 id="further-reading">Further reading</h2> -<ul> -<li><a href="http://modelviewculture.com/pieces/the-fantasy-and-abuse-of-the-manipulable-user">The Fantasy and Abuse of the Manipulable User</a></li> -<li><a href="https://glyph.twistedmatrix.com/2005/11/ethics-for-programmers-primum-non.html">Ethics for Programmers: Primum non Nocere</a></li> -<li><a href="http://idlewords.com/bt14.htm">The Internet with a Human Face</a></li> -<li><a href="http://www.diffen.com/difference/Ethics_vs_Morals">Ethics vs Morals</a></li> -<li><a href="http://yesmeansyesblog.wordpress.com">Yes means Yes</a></li> -</ul> -<h2 id="why-bother">Why bother?</h2> -<p>Everyone <em>thinks</em> they're doing good most of the time. Ethical codes help -guide that sense into alignment with the surrounding social and political -context: doing good for whom, why, and with what kinds of caveats.</p> -<h2 id="its-not-about-engineering-its-about-people">It's not about engineering, it's about people</h2> -<p>An ethical code for software development should not waste too much space -talking about <em>engineering practices</em>. Certainly there is value in getting -more developers and systems people to follow good engineering practice, but -an ethical code should focus on the interaction between trustworthiness, the -greater good, the personal good of <em>all</em> the participants in the system, and -software itself.</p> -<p>(This comes up in Ethics for Programmers, above.)</p> -<p>It's no good to build a wonderfully-engineered system that is cheap to run -and easy to integrate with if it systematically disenfranchises and abuses -its users for the benefit of its owners, and that's a problem we actually -have via Facebook, Github, Twitter, and numerous others.</p> -<h2 id="ethical-codes-are-fundamentally-extrinsic">Ethical codes are fundamentally extrinsic</h2> -<p>Ethical codes exist so that others can judge our behaviour, not so that we -can judge our own behaviour.</p> -<h2 id="ethical-codes-must-be-constraining">Ethical codes must be constraining</h2> -<p>Ethical codes do not exist in a vacuum. A code that authorizes its adherents -to behave in any way they see fit, subject only to their own judgement, is no -ethical code at all. We already have that and the results have not been great.</p> -<p><em>This is important</em> - a meaningful ethical code for software would probably -cripple most software business models. An ethical code that prioritizes -active consent, for example, completely cripples advertising and analytics, -and puts a big roadblock in buyouts like Instagram's. This may well be good -for society.</p> -<h2 id="integrity-is-not-about-contracts-or-legislation">Integrity is not about contracts or legislation</h2> -<p>Ethics, personal integrity, and group integrity are tangled together, but -modern Western conceptions of group integrity tend to revolve around “does -this group break the law or engender lawsuits,” not “does this group act in -the best interests of people outside of it.”</p> -<h2 id="assumptions">Assumptions</h2> -<p>I've embedded some of my personal morality into the “ethics” articles in this -section, in the absence of a published moral code. Those, obviously, aren't -absolute, but you can reason about their validity if you assume that I -believe the “end user's” privacy and active consent take priority over the -technical cleverness or business value of a software system.</p> -<h3 id="consent-and-social-software">Consent and social software</h3> -<p>This has some complicated downstream effects: “active consent” means -something you can't handwave away by putting implied consent (for example, to -future changes) in an EULA or privacy statement. I haven't written much that -calls out this pattern because it's <em>pervasive</em>.</p> -<p>The “end user is the real product” business model most social networks -operate on is fundamentally unethical under this code. It will always be more -valuable to the “real customers” (advertisers, analytics platforms, law -enforcement, and intelligence agencies) for users to be opted into new -measurements by default, <em>assuming</em> consent rather than obtaining it.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/ethics/musings.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/ethics/musings.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/git/_list.html b/.html/git/_list.html deleted file mode 100644 index 59ee1d4..0000000 --- a/.html/git/_list.html +++ /dev/null @@ -1,109 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /git - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">git</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /git</code></h1> - - - <div id="directories"> - <h2>Directories</h2> - <ul> - - <li><a href="theory-and-practice/">theory-and-practice/</a></li> - - </ul> - </div> - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="scratch">Git Is Not Magic</a></li> - - <li><a href="survival">Git Survival Guide</a></li> - - <li><a href="integrate">Integrating with Git: A Field Guide</a></li> - - <li><a href="pull-request-workflow">Life With Pull Requests</a></li> - - <li><a href="detached-sigs">Notes Towards Detached Signatures in Git</a></li> - - <li><a href="stop-using-git-pull-to-deploy">Stop Using Git Pull To Deploy</a></li> - - <li><a href="config">git-config Settings You Want</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/git">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/git/config.html b/.html/git/config.html deleted file mode 100644 index c21c4f5..0000000 --- a/.html/git/config.html +++ /dev/null @@ -1,151 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - git-config Settings You Want - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">git</a> - - </li> - - <li class="crumb-2 last"> - - config - - </li> - - </ol> - - - - <div id="article"> - <h1 id="git-config-settings-you-want">git-config Settings You Want</h1> -<p>Git comes with some fairly <a href="http://www.tux.org/lkml/">lkml</a>-specific -configuration defaults. You should fix this. All of the items below can be set -either for your entire login account (<code>git config --global</code>) or for a specific -repository (<code>git config</code>).</p> -<p>Full documentation is under <code>git help config</code>, unless otherwise stated.</p> -<ul> -<li> -<p><code>git config user.name 'Your Full Name'</code> and <code>git config user.email - 'your-email@example.com'</code>, obviously.</p> -</li> -<li> -<p><code>git config push.default simple</code> - the default behaviour (called <code>matching</code>) - of an unqualified <code>git push</code> is to identify pairs of branches by name and - push all matches from your local repository to the remote. Given that - branches have explicit “upstream” configuration identifying which, if any, - branch in which, if any, remote they're associated with, this is dumb. The - <code>simple</code> mode pushes the current branch to its upstream remote, if and only - if the local branch name and the remote branch name match <em>and</em> the local - branch tracks the remote branch. Requires Git 1.8 or later; will be the - default in Git 2.0. (For older versions of Git, use <code>upstream</code> instead, - which does not require that branch names match.)</p> -</li> -<li> -<p><code>git config merge.defaultToUpstream true</code> - causes an unqualified <code>git - merge</code> to merge the current branch's configured upstream branch, rather than - being an error. (<code>git rebase</code> always has this behaviour. Consistent!) You - should still merge thoughtfully.</p> -</li> -<li> -<p><code>git config rebase.autosquash true</code> - causes <code>git rebase -i</code> to parse magic - comments created by <code>git commit --squash=some-hash</code> and <code>git commit - --fixup=some-hash</code> and reorder the commit list before presenting it for - further editing. See the descriptions of “squash” and “fixup” in <code>git help - rebase</code> for details; autosquash makes amending commits other than the most - recent easier and less error-prone.</p> -</li> -<li> -<p><code>git config branch.autosetupmerge always</code> - newly-created branches whose - start point is a branch (<code>git checkout master -b some-feature</code>, <code>git branch - some-feature origin/develop</code>, and so on) will be configured to have the - start point branch as their upstream. By default (with <code>true</code> rather than - <code>always</code>) this only happens when the start point is a remote-tracking - branch.</p> -</li> -<li> -<p><code>git config rerere.enabled true</code> - enable “reuse recorded resolution.” The - <code>git help rerere</code> docs explain it pretty well, but the short version is that - git can record how you resolve conflicts during a “test” merge and reuse the - same approach when resolving the same conflict later, in a “real” merge.</p> -</li> -</ul> -<h2 id="for-advanced-users">For advanced users</h2> -<p>A few things are nice when you're getting started, but become annoying when -you no longer need them.</p> -<ul> -<li><code>git config advice.detachedHead</code> - if you already understand the difference - between having a branch checked out and having a commit checked out, and - already understand what “detatched head” means, the warning on every <code>git - checkout ...some detatched thing...</code> isn't helping anyone. This is also - useful repositories used for deployment, where specific commits (from tags, - for example) are regularly checked out.</li> -</ul> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/git/config.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/git/config.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/git/detached-sigs.html b/.html/git/detached-sigs.html deleted file mode 100644 index a3e439d..0000000 --- a/.html/git/detached-sigs.html +++ /dev/null @@ -1,359 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Notes Towards Detached Signatures in Git - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">git</a> - - </li> - - <li class="crumb-2 last"> - - detached-sigs - - </li> - - </ol> - - - - <div id="article"> - <h1 id="notes-towards-detached-signatures-in-git">Notes Towards Detached Signatures in Git</h1> -<p>Git supports a limited form of object authentication: specific object -categories in Git's internal model can have <a href="../gpg/terrible">GPG</a> signatures -embedded in them, allowing the authorship of the objects to be verified using -<a href="../gpg/cool">GPG</a>'s underlying trust model. Tag signatures can be used to -verify the authenticity and integrity of the <em>snapshot associated with a -tag</em>, and the authenticity of the tag itself, filling a niche broadly similar -to code signing in binary distribution systems. Commit signatures can be used -to verify the authenticity of the <em>snapshot associated with the commit</em>, and -the authorship of the commit itself. (Conventionally, commit signatures are -assumed to also authenticate either the entire line of history leading to a -commit, or the diff between the commit and its first parent, or both.)</p> -<p>Git's existing system has some tradeoffs.</p> -<ul> -<li> -<p>Signatures are embedded within the objects they sign. The signature is part - of the object's identity; since Git is content-addressed, this means that - an object can neither be retroactively signed nor retroactively stripped of - its signature without modifying the object's identity. Git's distributed - model means that these sorts of identity changes are both complicated and - easily detected.</p> -</li> -<li> -<p>Commit signatures are second-class citizens. They're a relatively recent - addition to the Git suite, and both the implementation and the social - conventions around them continue to evolve.</p> -</li> -<li> -<p>Only some objects can be signed. While Git has relatively weak rules about - workflow, the signature system assumes you're using one of Git's more - widespread workflows by limiting your options to at most one signature, and - by restricting signatures to tags and commits (leaving out blobs, trees, - and refs).</p> -</li> -</ul> -<p>I believe it would be useful from an authentication standpoint to add -"detached" signatures to Git, to allow users to make these tradeoffs -differently if desired. These signatures would be stored as separate (blob) -objects in a dedicated <code>refs</code> namespace, supporting retroactive signatures, -multiple signatures for a given object, "policy" signatures, and -authentication of arbitrary objects.</p> -<p>The following notes are partially guided by Git's one existing "detached -metadata" facility, <code>git notes</code>. Similarities are intentional; divergences -will be noted where appropriate. Detached signatures are meant to -interoperate with existing Git workflow as much as possible: in particular, -they can be fetched and pushed like any other bit of Git metadata.</p> -<p>A detached signature cryptographically binds three facts together into an -assertion whose authenticity can be checked by anyone with access to the -signatory's keys:</p> -<ol> -<li>An object (in the Git sense; a commit, tag, tree, or blob),</li> -<li>A policy label, and</li> -<li>A signatory (a person or agent making the assertion).</li> -</ol> -<p>These assertions can be published separately from or in tandem with the -objects they apply to.</p> -<h2 id="policies">Policies</h2> -<p>Taking a hint from Monotone, every signature includes a "policy" identifying -how the signature is meant to be interpreted. Policies are arbitrary strings; -their meaning is entirely defined by tooling and convention, not by this -draft.</p> -<p>This draft uses a single policy, <code>author</code>, for its examples. A signature -under the <code>author</code> policy implies that the signatory had a hand in the -authorship of the designated object. (This is compatible with existing -interpretations of signed tags and commits.) (Authorship under this model is -strictly self-attested: you can claim authorship of anything, and you cannot -assert anyone else's authorship.)</p> -<p>The Monotone documentation suggests a number of other useful policies related -to testing and release status, automated build results, and numerous other -factors. Use your imagination.</p> -<h2 id="whats-in-a-signature">What's In A Signature</h2> -<p>Detached signatures cover the disk representation of an object, as given by</p> -<pre><code>git cat-file <TYPE> <SHA1> -</code></pre> -<p>For most of Git's object types, this means that the signed content is plain -text. For <code>tree</code> objects, the signed content is the awful binary -representation of the tree, <em>not</em> the pretty representation given by <code>git -ls-tree</code> or <code>git show</code>.</p> -<p>Detached signatures include the "policy" identifier in the signed content, to -prevent others from tampering with policy choices via <code>refs</code> hackery. (This -will make more sense momentarily.) The policy identifier is prepended to the -signed content, terminated by a zero byte (as with Git's own type -identifiers, but without a length field as length checks are performed by -signing and again when the signature is stored in Git).</p> -<p>To generate the <em>complete</em> signable version of an object, use something -equivalent to the following shell snippet:</p> -<pre><code># generate-signable POLICY TYPE SHA1 -function generate-signable() { - echo -n "$1" - SOMETHING OUTPUTTING A NUL HERE - git cat-file "$2" "$3" -} -</code></pre> -<p>(In the process of writing this, I discovered how hard it is to get Unix's -C-derived shell tools to emit a zero byte.)</p> -<h2 id="signature-storage-and-naming">Signature Storage and Naming</h2> -<p>We assume that a userid will sign an object at most once.</p> -<p>Each signature is stored in an independent blob object in the repository it -applies to. The signature object (described above) is stored in Git, and its -hash recorded in <code>refs/signatures/<POLICY>/<SUBJECT SHA1>/<SIGNER KEY -FINGERPRINT></code>.</p> -<pre><code># sign POLICY TYPE SHA1 FINGERPRINT -function sign() { - local SIG_HASH=$( - generate-signable "$@" | - gpg --batch --no-tty --sign -u "$4" | - git hash-object --stdin -w -t blob - ) - git update-ref "refs/signatures/$1/$3/$4" -} -</code></pre> -<p>Stored signatures always use the complete fingerprint to identify keys, to -minimize the risk of colliding key IDs while avoiding the need to store full -keys in the <code>refs</code> naming hierarchy.</p> -<p>The policy name can be reliably extracted from the ref, as the trailing part -has a fixed length (in both path segments and bytes) and each ref begins with -a fixed, constant prefix <code>refs/signatures/</code>.</p> -<h2 id="signature-verification">Signature Verification</h2> -<p>Given a signature ref as described above, we can verify and authenticate the -signature and bind it to the associated object and policy by performing the -following check:</p> -<ol> -<li>Pick apart the ref into policy, SHA1, and key fingerprint parts.</li> -<li>Reconstruct the signed body as above, using the policy name extracted from - the ref.</li> -<li>Retrieve the signature from the ref and combine it with the object itself.</li> -<li>Verify that the policy in the stored signature matches the policy in the - ref.</li> -<li> -<p>Verify the signature with GPG:</p> -<pre><code># verify-gpg POLICY TYPE SHA1 FINGERPRINT -verify-gpg() { - { - git cat-file "$2" "$3" - git cat-file "refs/signatures/$1/$3/$4" - } | gpg --batch --no-tty --verify -} -</code></pre> -</li> -<li> -<p>Verify the key fingerprint of the signing key matches the key fingerprint - in the ref itself.</p> -</li> -</ol> -<p>The specific rules for verifying the signature in GPG are left up to the user -to define; for example, some sites may want to auto-retrieve keys and use a -web of trust from some known roots to determine which keys are trusted, while -others may wish to maintain a specific, known keyring containing all signing -keys for each policy, and skip the web of trust entirely. This can be -accomplished via <code>git-config</code>, given some work, and via <code>gpg.conf</code>.</p> -<h2 id="distributing-signatures">Distributing Signatures</h2> -<p>Since each signature is stored in a separate ref, and since signatures are -<em>not</em> expected to be amended once published, the following refspec can be -used with <code>git fetch</code> and <code>git push</code> to distribute signatures:</p> -<pre><code>refs/signatures/*:refs/signatures/* -</code></pre> -<p>Note the lack of a <code>+</code> decoration; we explicitly do not want to auto-replace -modified signatures, normally; explicit user action should be required.</p> -<h2 id="workflow-notes">Workflow Notes</h2> -<p>There are two verification workflows for signatures: "static" verification, -where the repository itself already contains all the refs and objects needed -for signature verification, and "pre-receive" verification, where an object -and its associated signature may be being uploaded at the same time.</p> -<p><em>It is impractical to verify signatures on the fly from an <code>update</code> hook</em>. -Only <code>pre-receive</code> hooks can usefully accept or reject ref changes depending -on whether the push contains a signature for the pushed objects. (Git does -not provide a good mechanism for ensuring that signature objects are pushed -before their subjects.) Correctly verifying object signatures during -<code>pre-receive</code> regardless of ref order is far too complicated to summarize -here.</p> -<h2 id="attacks">Attacks</h2> -<h3 id="lies-of-omission">Lies of Omission</h3> -<p>It's trivial to hide signatures by deleting the signature refs. Similarly, -anyone with access to a repository can delete any or all detached signatures -from it without otherwise invalidating the signed objects.</p> -<p>Since signatures are mostly static, sites following the recommended no-force -policy for signature publication should only be affected if relatively recent -signatures are deleted. Older signatures should be available in one or more -of the repository users' loca repositories; once created, a signature can be -legitimately obtained from anywhere, not only from the original signatory.</p> -<p>The signature naming protocol is designed to resist most other forms of -assertion tampering, but straight-up omission is hard to prevent.</p> -<h3 id="unwarranted-certification">Unwarranted Certification</h3> -<p>The <code>policy</code> system allows any signatory to assert any policy. While -centralized signature distribution points such as "release" repositories can -make meaningful decisions about which signatures they choose to accept, -publish, and propagate, there's no way to determine after the fact whether a -policy assertion was obtained from a legitimate source or a malicious one -with no grounds for asserting the policy.</p> -<p>For example, I could, right now, sign an <code>all-tests-pass</code> policy assertion -for the Linux kernel. While there's no chance on Earth that the LKML team -would propagate that assertion, if I can convince you to fetch signatures -from my repository, you will fetch my bogus assertion. If <code>all-tests-pass</code> is -a meaningful policy assertion for the Linux kernel, then you will have very -few options besides believing that I assert that all tests have passed.</p> -<h3 id="ambigiuous-policy">Ambigiuous Policy</h3> -<p>This is an ongoing problem with crypto policy systems and user interfaces -generally, but this design does <em>nothing</em> to ensure that policies are -interpreted uniformly by all participants in a repository. In particular, -there's no mechanism described for distributing either prose or programmatic -policy definitions and checks. All policy information is out of band.</p> -<p>Git already has ambiguity problems around commit signing: there are multiple -ways to interpret a signature on a commit:</p> -<ol> -<li> -<p>I assert that this snapshot and commit message were authored as described - in this commit's metadata. (In this interpretation, the signature's - authenticity guarantees do <em>not</em> transitively apply to parents.)</p> -</li> -<li> -<p>I assert that this snapshot and commit message were authored as described - in this commit's metadata, based on exactly the parent commits described. - (In this interpretation, the signature's authenticity guarantees <em>do</em> - transitively apply to parents. This is the interpretation favoured by XXX - LINK HERE XXX.)</p> -</li> -<li> -<p>I assert that this <em>diff</em> and commit message was authored as described in - this commit's metadata. (No assertions about the <em>snapshot</em> are made - whatsoever, and assertions about parentage are barely sensical at all. - This meshes with widespread, diff-oriented policies.)</p> -</li> -</ol> -<h3 id="grafts-and-replacements">Grafts and Replacements</h3> -<p>Git permits post-hoc replacement of arbitrary objects via both the grafts -system (via an untracked, non-distributed file in <code>.git</code>, though some -repositories distribute graft lists for end-users to manually apply) and the -replacements system (via <code>refs/replace/<SHA1></code>, which can optionally be -fetched or pushed). The interaction between these two systems and signature -verification needs to be <em>very</em> closely considered; I've not yet done so.</p> -<p>Cases of note:</p> -<ul> -<li>Neither signature nor subject replaced - the "normal" case</li> -<li>Signature not replaced, subject replaced (by graft, by replacement, by both)</li> -<li>Signature replaced, subject not replaced</li> -<li>Both signature and subject replaced</li> -</ul> -<p>It's tempting to outright disable <code>git replace</code> during signing and -verification, but this will have surprising effects when signing a ref-ish -instead of a bare hash. Since this is the <em>normal</em> case, I think this merits -more thought. (I'm also not aware of a way to disable grafts without -modifying <code>.git</code>, and having the two replacement mechanisms treated -differently may be dangerous.)</p> -<h3 id="no-signed-refs">No Signed Refs</h3> -<p>I mentioned early in this draft that Git's existing signing system doesn't -support signing refs themselves; since refs are an important piece of Git's -workflow ecosystem, this may be a major omission. Unfortunately, this -proposal doesn't address that.</p> -<h2 id="possible-refinements">Possible Refinements</h2> -<ul> -<li>Monotone's certificate system is key+value based, rather than label-based. - This might be useful; while small pools of related values can be asserted - using mutually exclusive policy labels (whose mutual exclusion is a matter - of local interpretation), larger pools of related values rapidly become - impractical under the proposed system.</li> -</ul> -<p>For example, this proposal would be inappropriate for directly asserting - third-party authorship; the asserted author would have to appear in the - policy name itself, exposing the user to a potentially very large number of - similar policy labels.</p> -<ul> -<li> -<p>Ref signing via a manifest (a tree constellation whose paths are ref names - and whose blobs sign the refs' values). Consider cribbing DNSSEC here for - things like lightweight absence assertions, too.</p> -</li> -<li> -<p>Describe how this should interact with commit-duplicating and - commit-rewriting workflows.</p> -</li> -</ul> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/git/detached-sigs.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/git/detached-sigs.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/git/index.html b/.html/git/index.html deleted file mode 100644 index 59ee1d4..0000000 --- a/.html/git/index.html +++ /dev/null @@ -1,109 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /git - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">git</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /git</code></h1> - - - <div id="directories"> - <h2>Directories</h2> - <ul> - - <li><a href="theory-and-practice/">theory-and-practice/</a></li> - - </ul> - </div> - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="scratch">Git Is Not Magic</a></li> - - <li><a href="survival">Git Survival Guide</a></li> - - <li><a href="integrate">Integrating with Git: A Field Guide</a></li> - - <li><a href="pull-request-workflow">Life With Pull Requests</a></li> - - <li><a href="detached-sigs">Notes Towards Detached Signatures in Git</a></li> - - <li><a href="stop-using-git-pull-to-deploy">Stop Using Git Pull To Deploy</a></li> - - <li><a href="config">git-config Settings You Want</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/git">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/git/integrate.html b/.html/git/integrate.html deleted file mode 100644 index 828019f..0000000 --- a/.html/git/integrate.html +++ /dev/null @@ -1,118 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Integrating with Git: A Field Guide - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">git</a> - - </li> - - <li class="crumb-2 last"> - - integrate - - </li> - - </ol> - - - - <div id="article"> - <h1 id="integrating-with-git-a-field-guide">Integrating with Git: A Field Guide</h1> -<p>Pretty much everything you might want to do to a Git repository when writing -tooling or integrations should be done by shelling out to one <code>git</code> command or -another.</p> -<h2 id="finding-gits-trees">Finding Git's trees</h2> -<p>Git commands can be invoked from locations other than the root of the work -tree or git directory. You can find either of those by invoking <code>git -rev-parse</code>.</p> -<p>To find the absolute path to the root of the work tree:</p> -<pre><code>git rev-parse --show-toplevel -</code></pre> -<p>This will output the absolute path to the root of the work tree on standard -output, followed by a newline. Since the work tree's absolute path can contain -whitespace (including newlines), you should assume every byte of output save -the final newline is part of the path, and if you're using this in a shell -script, quote defensively.</p> -<p>To find the relative path from the current working directory:</p> -<pre><code>git rev-parse --show-cdup -</code></pre> -<p>This will output the relative path to the root of the work tree on standard -output, followed by a newline.</p> -<p>For bare repositories, both commands will output nothing and exit with a zero -status. (Surprise!)</p> -<p>To find <em>a</em> path to the root of the git directory:</p> -<pre><code>git rev-parse --git-dir -</code></pre> -<p>This will output either the relative or the absolute path to the git -directory, followed by a newline.</p> -<p>All three of these commands will exit with non-zero status when run outside of -a work tree or git directory. Check for it.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/git/integrate.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/git/integrate.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/git/pull-request-workflow.html b/.html/git/pull-request-workflow.html deleted file mode 100644 index 1a15642..0000000 --- a/.html/git/pull-request-workflow.html +++ /dev/null @@ -1,163 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Life With Pull Requests - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">git</a> - - </li> - - <li class="crumb-2 last"> - - pull-request-workflow - - </li> - - </ol> - - - - <div id="article"> - <h1 id="life-with-pull-requests">Life With Pull Requests</h1> -<p>I've been party to a number of discussions with folks contributing to -pull-request-based projects on Github (and other hosts, but mostly Github). -Because of Git's innate flexibility, there are lots of ways to work with pull -requests. Here's mine.</p> -<p>I use a couple of naming conventions here that are not stock <code>git</code>:</p> -<dl> -<dt>origin</dt> -<dd>The repository to which you <em>publish</em> proposed changes</dd> -<dt>upstream</dt> -<dd>The repository from which you receive ongoing development, and which will -receive your changes.</dd> -</dl> -<h2 id="one-time-setup">One-time setup</h2> -<p>Do these things once, when starting out on a project. Keep the results around -for later.</p> -<p>I'll be referring to the original project repository as <code>upstream</code> and -pretending its push URL is <code>UPSTREAM-URL</code> below. In real life, the URL will -often be something like <code>git@github.com:someguy/project.git</code>.</p> -<h3 id="fork-the-project">Fork the project</h3> -<p>Use the repo manager's forking tool to create a copy of the project in your -own namespace. This generally creates your copy with a bunch of useless tat; -feel free to ignore all of this, as the only purpose of this copy is to -provide somewhere for <em>you</em> to publish <em>your</em> changes.</p> -<p>We'll be calling this repository <code>origin</code> later. Assume it has a URL, which -I'll abbreviate <code>ORIGIN-URL</code>, for <code>git push</code> to use.</p> -<p>(You can leave this step for later, but if you know you're going to do it, why -not get it out of the way?)</p> -<h3 id="clone-the-project-and-configure-it">Clone the project and configure it</h3> -<p>You'll need a clone locally to do work in. Create one from <code>origin</code>:</p> -<pre><code>git clone ORIGIN-URL some-local-name -</code></pre> -<p>While you're here, <code>cd</code> into it and add the original project as a remote:</p> -<pre><code>cd some-local-name -git remote add upstream UPSTREAM-URL -</code></pre> -<h2 id="feature-process">Feature process</h2> -<p>Do these things for each feature you work on. To switch features, just use -<code>git checkout my-feature</code>.</p> -<h3 id="create-a-new-feature-branch-locally">Create a new feature branch locally</h3> -<p>We use <code>upstream</code>'s <code>master</code> branch here, so that your feature includes all of -<code>upstream</code>'s state initially. We also need to make sure our local cache of -<code>upstream</code>'s state is correct:</p> -<pre><code>git fetch upstream -git checkout upstream/master -b my-feature -</code></pre> -<h3 id="do-work">Do work</h3> -<p>If you need my help here, stop now.</p> -<h3 id="integrate-upstream-changes">Integrate upstream changes</h3> -<p>If you find yourself needing something that's been added upstream, use -<em>rebase</em> to integrate it to avoid littering your feature branch with -“meaningless” merge commits.</p> -<pre><code>git checkout my-feature -git fetch upstream -git rebase upstream/master -</code></pre> -<h3 id="publish-your-branch">Publish your branch</h3> -<p>When you're “done,” publish your branch to your personal repository:</p> -<pre><code>git push origin my-feature -</code></pre> -<p>Then visit your copy in your repo manager's web UI and create a pull request -for <code>my-feature</code>.</p> -<h3 id="integrating-feedback">Integrating feedback</h3> -<p>Very likely, your proposed changes will need work. If you use history-editing -to integrate feedback, you will need to use <code>--force</code> when updating the -branch:</p> -<pre><code>git push --force origin my-feature -</code></pre> -<p>This is safe provided two things are true:</p> -<ol> -<li><strong>The branch has not yet been merged to the upstream repo.</strong></li> -<li>You are only force-pushing to your fork, not to the upstream repo.</li> -</ol> -<p>Generally, no other users will have work based on your pull request, so -force-pushing history won't cause problems.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/git/pull-request-workflow.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/git/pull-request-workflow.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/git/scratch.html b/.html/git/scratch.html deleted file mode 100644 index ff1bdff..0000000 --- a/.html/git/scratch.html +++ /dev/null @@ -1,134 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Git Is Not Magic - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">git</a> - - </li> - - <li class="crumb-2 last"> - - scratch - - </li> - - </ol> - - - - <div id="article"> - <h1 id="git-is-not-magic">Git Is Not Magic</h1> -<p>I'm bored. Let's make a git repository out of whole cloth.</p> -<p>Git repos are stored in .git:</p> -<pre><code>fakegit$ mkdir .git -</code></pre> -<p>They have a “symbolic ref” (which are text files, see <a href="http://jk.gs/git-symbolic-ref.html"><code>man -git-symbolic-ref</code></a>) named <code>HEAD</code>, pointing -to the currently checked-out branch. Let's use <code>master</code>. Branches are refs -under <code>refs/heads</code> (see <a href="http://jk.gs/git-branch.html"><code>man git-branch</code></a>):</p> -<pre><code>fakegit ((unknown))$ echo 'ref: refs/heads/master' > .git/HEAD -</code></pre> -<p>The have an object database and a refs database, both of which are simple -directories (see <a href="http://jk.gs/gitrepository-layout.html"><code>man -gitrepository-layout</code></a> and <a href="http://jk.gs/gitrevisions.html"><code>man -gitrevisions</code></a>). Let's also enable the reflog, -because it's a great safety net if you use history-editing tools in git:</p> -<pre><code>fakegit ((ref: re...))$ mkdir .git/refs .git/objects .git/logs -fakegit (master #)$ -</code></pre> -<p>Now <code>__git_ps1</code>, at least, is convinced that we have a working git repository. -Does it work?</p> -<pre><code>fakegit (master #)$ echo 'Hello, world!' > hello.txt -fakegit (master #)$ git add hello.txt -fakegit (master #)$ git commit -m 'Initial commit' -[master (root-commit) 975307b] Initial commit -1 file changed, 1 insertion(+) -create mode 100644 hello.txt - -fakegit (master)$ git log -commit 975307ba0485bff92e295e3379a952aff013c688 -Author: Owen Jacobson <owen.jacobson@grimoire.ca> -Date: Wed Feb 6 10:07:07 2013 -0500 - - Initial commit -</code></pre> -<p><a href="https://www.youtube.com/watch?v=3VwVpaWUu30">Eeyup</a>.</p> -<hr> -<p>Should you do this? <strong>Of course not.</strong> Anywhere you could run these commands, -you could instead run <code>git init</code> or <code>git clone</code>, which set up a number of -other structures, including <code>.git/config</code> and any unusual permissions options. -The key part here is that a directory's identity as “a git repository” is -entirely a function of its contents, not of having been blessed into being by -<code>git</code> itself.</p> -<p>You can infer a lot from this: for example, you can infer that it's “safe” to -move git repositories around using FS tools, or to back them up with the same -tools, for example. This is not as obvious to everyone as you might hope; people </p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/git/scratch.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/git/scratch.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/git/stop-using-git-pull-to-deploy.html b/.html/git/stop-using-git-pull-to-deploy.html deleted file mode 100644 index a3736a0..0000000 --- a/.html/git/stop-using-git-pull-to-deploy.html +++ /dev/null @@ -1,178 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Stop Using Git Pull To Deploy - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">git</a> - - </li> - - <li class="crumb-2 last"> - - stop-using-git-pull-to-deploy - - </li> - - </ol> - - - - <div id="article"> - <h1 id="stop-using-git-pull-for-deployment">Stop using <code>git pull</code> for deployment!</h1> -<h2 id="the-problem">The problem</h2> -<ul> -<li>You have a Git repository containing your project.</li> -<li>You want to “deploy” that code when it changes.</li> -<li>You'd rather not download the entire project from scratch for each - deployment.</li> -</ul> -<h2 id="the-antipattern">The antipattern</h2> -<p>“I know, I'll use <code>git pull</code> in my deployment script!”</p> -<p>Stop doing this. Stop teaching other people to do this. It's wrong, and it -will eventually lead to deploying something you didn't want.</p> -<p>Deployment should be based on predictable, known versions of your code. -Ideally, every deployable version has a tag (and you deploy exactly that tag), -but even less formal processes, where you deploy a branch tip, should still be -deploying exactly the code designated for release. <code>git pull</code>, however, can -introduce new commits.</p> -<p><code>git pull</code> is a two-step process:</p> -<ol> -<li>Fetch the current branch's designated upstream remote, to obtain all of the - remote's new commits.</li> -<li>Merge the current branch's designated upstream branch into the current - branch.</li> -</ol> -<p>The merge commit means the actual deployed tree might <em>not</em> be identical to -the intended deployment tree. Local changes (intentional or otherwise) will be -preserved (and merged) into the deployment, for example; once this happens, -the actual deployed commit will <em>never</em> match the intended commit.</p> -<p><code>git pull</code> will approximate the right thing “by accident”: if the current -local branch (generally <code>master</code>) for people using <code>git pull</code> is always clean, -and always tracks the desired deployment branch, then <code>git pull</code> will update -to the intended commit exactly. This is pretty fragile, though; many git -commands can cause the local branch to diverge from its upstream branch, and -once that happens, <code>git pull</code> will always create new commits. You can patch -around the fragility a bit using the <code>--ff-only</code> option, but that only tells -you when your deployment environment has diverged and doesn't fix it.</p> -<h2 id="the-right-pattern">The right pattern</h2> -<p>Quoting <a href="http://gitolite.com/the-list-and-irc/deploy.html">Sitaram Chamarty</a>:</p> -<blockquote> -<p>Here's what we expect from a deployment tool. Note the rule numbers -- -we'll be referring to some of them simply by number later.</p> -<ol> -<li> -<p>All files in the branch being deployed should be copied to the - deployment directory.</p> -</li> -<li> -<p>Files that were deleted in the git repo since the last deployment - should get deleted from the deployment directory.</p> -</li> -<li> -<p>Any changes to tracked files in the deployment directory after the - last deployment should be ignored when following rules 1 and 2.</p> -<p>However, sometimes you might want to detect such changes and abort if -you found any.</p> -</li> -<li> -<p>Untracked files in the deploy directory should be left alone.</p> -<p>Again, some people might want to detect this and abort the deployment.</p> -</li> -</ol> -</blockquote> -<p>Sitaram's own documentation talks about how to accomplish these when -“deploying” straight out of a bare repository. That's unwise (not to mention -impractical) in most cases; deployment should use a dedicated clone of the -canonical repository.</p> -<p>I also disagree with point 3, preferring to keep deployment-related changes -outside of tracked files. This makes it much easier to argue that the changes -introduced to configure the project for deployment do not introduce new bugs -or other surprise features.</p> -<p>My deployment process, given a dedicated clone at <code>$DEPLOY_TREE</code>, is as -follows:</p> -<pre><code>cd "${DEPLOY_TREE}" -git fetch --all -git checkout --force "${TARGET}" -# Following two lines only required if you use submodules -git submodule sync -git submodule update --init --recursive -# Follow with actual deployment steps (run fabric/capistrano/make/etc) -</code></pre> -<p><code>$TARGET</code> is either a tag name (<code>v1.2.1</code>) or a remote branch name -(<code>origin/master</code>), but could also be a commit hash or anything else Git -recognizes as a revision. This will detach the head of the <code>$DEPLOY_TREE</code> -repository, which is fine as no new changes should be authored in this -repository (so the local branches are irrelevant). The warning Git emits when -<code>HEAD</code> becomes detached is unimportant in this case.</p> -<p>The tracked contents of <code>$DEPLOY_TREE</code> will end up identical to the desired -commit, discarding local changes. The pattern above is very similar to what -most continuous integration servers use when building from Git repositories, -for much the same reason.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/git/stop-using-git-pull-to-deploy.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/git/stop-using-git-pull-to-deploy.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/git/survival.html b/.html/git/survival.html deleted file mode 100644 index c1d43ac..0000000 --- a/.html/git/survival.html +++ /dev/null @@ -1,174 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Git Survival Guide - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">git</a> - - </li> - - <li class="crumb-2 last"> - - survival - - </li> - - </ol> - - - - <div id="article"> - <h1 id="git-survival-guide">Git Survival Guide</h1> -<p>I think the <code>git</code> UI is pretty awful, and encourages using Git in ways that -will screw you. Here are a few things I've picked up that have saved my bacon.</p> -<ul> -<li>You will inevitably need to understand Git's “internals” to make use of it - as an SCM tool. Accept this early. If you think your SCM tool should not - expose you to so much plumbing, <a href="http://mercurial.selenic.com">don't</a> - <a href="http://bazaar.canonical.com">use</a> <a href="http://subversion.apache.org">Git</a>.<ul> -<li>Git weenies will claim that this plumbing is what gives Git all of its - extra power. This is true; it gives Git the power to get you out of - situations you wouldn't be in without Git.</li> -</ul> -</li> -<li><code>git log --graph --decorate --oneline --color --all</code></li> -<li>Run <code>git fetch</code> habitually. Stale remote-tracking branches lead to sadness.</li> -<li><code>git push</code> and <code>git pull</code> are <strong>not symmetric</strong>. <code>git push</code>'s - opposite operation is <code>git fetch</code>. (<code>git pull</code> is equivalent to <code>git fetch</code> - followed by <code>git merge</code>, more or less).</li> -<li><a href="config">Git configuration values don't always have the best defaults</a>.</li> -<li>The upstream branch of <code>foo</code> is <code>foo@{u}</code>. The upstream branch of your - checked-out branch is <code>HEAD@{u}</code> or <code>@{u}</code>. This is documented in <code>git help - revisions</code>.</li> -<li>You probably don't want to use a merge operation (such as <code>git pull</code>) to - integrate upstream changes into topic branches. The resulting history can be - very confusing to follow, especially if you integrate upstream changes - frequently.<ul> -<li>You can leave topic branches “real” relatively safely. You can do - a test merge to see if they still work cleanly post-integration without - actually integrating upstream into the branch permanently.</li> -<li>You can use <code>git rebase</code> or <code>git pull --rebase</code> to transplant your - branch to a new, more recent starting point that includes the changes - you want to integrate. This makes the upstream changes a permanent part - of your branch, just like <code>git merge</code> or <code>git pull</code> would, but generates - an easier-to-follow history. Conflict resolution will happen as normal.</li> -</ul> -</li> -<li> -<p>Example test merge, using <code>origin/master</code> as the upstream branch and <code>foo</code> - as the candidate for integration:</p> -<pre><code>git fetch origin -git checkout origin/master -b test-merge-foo -git merge foo -# run tests, examine files -git diff origin/master..HEAD -</code></pre> -<p>To discard the test merge, delete the branch after checking out some other -branch:</p> -<pre><code>git checkout foo -git branch -D test-merge-foo -</code></pre> -<p>You can combine this with <code>git rerere</code> to save time resolving conflicts in -a later “real,” permanent merge.</p> -</li> -<li> -<p>You can use <code>git checkout -p</code> to build new, tidy commits out of a branch - laden with “wip” commits:</p> -<pre><code>git fetch -git checkout $(git merge-base origin/master foo) -b foo-cleaner-history -git checkout -p foo -- paths/to/files -# pick out changes from the presented patch that form a coherent commit -# repeat 'git checkout -p foo --' steps for related files to build up -# the new commit -git commit -# repeat 'git checkout -p foo --' and 'git commit' steps until no diffs remain -</code></pre> -<ul> -<li>Gotcha: <code>git checkout -p</code> will do nothing for files that are being - created. Use <code>git checkout</code>, instead, and edit the file if necessary. - Thanks, Git.</li> -<li>Gotcha: The new, clean branch must diverge from its upstream branch - (<code>origin/master</code>, in the example above) at exactly the same point, or - the diffs presented by <code>git checkout -p foo</code> will include chunks that - revert changes on the upstream branch since the “dirty” branch was - created. The easiest way to find this point is with <code>git merge-base</code>.</li> -</ul> -</li> -</ul> -<h2 id="useful-resources">Useful Resources</h2> -<p>That is, resoures that can help you solve problems or understand things, not -resources that reiterate the man pages for you.</p> -<ul> -<li>Sitaram Chamarty's <a href="http://sitaramc.github.com/gcs/">git concepts - simplified</a></li> -<li>Tv's <a href="http://eagain.net/articles/git-for-computer-scientists">Git for Computer - Scientists</a></li> -</ul> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/git/survival.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/git/survival.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/git/theory-and-practice/_list.html b/.html/git/theory-and-practice/_list.html deleted file mode 100644 index feae190..0000000 --- a/.html/git/theory-and-practice/_list.html +++ /dev/null @@ -1,96 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /git/theory-and-practice - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="../">git</a> - - </li> - - <li class="crumb-2 not-last"> - - <a href="./">theory-and-practice</a> - - </li> - - <li class="crumb-3 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /git/theory-and-practice</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="objects">Objects</a></li> - - <li><a href="refs-and-names">Refs and Names</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/git/theory-and-practice">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/git/theory-and-practice/index.html b/.html/git/theory-and-practice/index.html deleted file mode 100644 index 297cbd9..0000000 --- a/.html/git/theory-and-practice/index.html +++ /dev/null @@ -1,126 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Git Internals 101 - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="../">git</a> - - </li> - - <li class="crumb-2 last"> - - theory-and-practice - - </li> - - </ol> - - - - <div id="article"> - <h1 id="git-internals-101">Git Internals 101</h1> -<p>Yeah, yeah, another article about “how Git works.” There are tons of these -already. Personally, I'm fond of Sitaram Chamarty's <a href="http://gitolite.com/master-toc.html">fantastic series of -articles</a> explaining Git from both ends, -and of <a href="http://eagain.net/articles/git-for-computer-scientists/">Git for Computer -Scientists</a>. Maybe -you'd rather read those.</p> -<p>This page was inspired by very specific, recurring issues I've run into while -helping people use Git. I think Git's “porcelain” layer -- its user interface --- is terrible, and does a bad job of insulating non-expert users from Git's -internals. While I'd love to fix that (and I do contribute to discussions on -that front, too), we still have the <code>git(1)</code> UI right now and people still get -into trouble with it right now.</p> -<p>Git follows the New Jersey approach laid out in Richard Gabriel's <a href="http://www.dreamsongs.com/RiseOfWorseIsBetter.html">The Rise of -“Worse is Better”</a>: given -the choice between a simple implementation and a simple interface, Git chooses -the simple implementation almost everywhere. This internal simplicity can give -users the leverage to fix the problems that its horrible user interface leads -them into, so these pages will focus on explaining the simple parts and giving -users the tools to examine them.</p> -<p>Throughout these articles, I've written “Git does X” a lot. Git is -<em>incredibly</em> configurable; read that as “Git does X <em>by default</em>.” I'll try to -call out relevant configuration options as I go, where it doesn't interrupt -the flow of knowledge.</p> -<ul> -<li><a href="objects">Objects</a></li> -<li><a href="refs-and-names">Refs and Names</a></li> -</ul> -<p>By the way, if you think you're just going to follow the -<a href="http://git-scm.com/documentation">many</a> -<a href="http://www.atlassian.com/git/tutorial">excellent</a> -<a href="http://try.github.io/levels/1/challenges/1">git</a> -<a href="https://www.kernel.org/pub/software/scm/git/docs/gittutorial.html">tutorials</a> -out there and that you won't need this knowledge, well, you will. You can -either learn it during a quiet time, when you can think and experiment, or you -can learn it when something's gone wrong, and everyone's shouting at each -other. Git's high-level interface doesn't do much to keep you on the sensible -path, and you will eventually need to fix something.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/git/theory-and-practice/index.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/git/theory-and-practice/index.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/git/theory-and-practice/objects.html b/.html/git/theory-and-practice/objects.html deleted file mode 100644 index ff6c53b..0000000 --- a/.html/git/theory-and-practice/objects.html +++ /dev/null @@ -1,202 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Objects - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="../">git</a> - - </li> - - <li class="crumb-2 not-last"> - - <a href="./">theory-and-practice</a> - - </li> - - <li class="crumb-3 last"> - - objects - - </li> - - </ol> - - - - <div id="article"> - <h1 id="objects">Objects</h1> -<p>Git's basest level is a storage and naming system for things Git calls -“objects.” These objects hold the bulk of the data about files and projects -tracked by Git: file contents, directory trees, commits, and so on. Every -object is identified by a SHA-1 hash, which is derived from its contents.</p> -<p>SHA-1 hashes are obnoxiously long, so Git allows you to substitue any unique -prefix of a SHA-1 hash, so long as it's at least four characters long. If the -hash <code>0b43b9e3e64793f5a222a644ed5ab074d8fa1024</code> is present in your repository, -then Git commands will understand <code>0b43</code>, <code>0b43b9</code>, and other patterns to all -refer to the same object, so long as no other object has the same SHA-1 -prefix.</p> -<h2 id="blobs">Blobs</h2> -<p>The contents of every file that's ever been stored in a Git repository are -stored as <code>blob</code> objects. These objects are very simple: they contain the file -contents, byte for byte.</p> -<h2 id="trees">Trees</h2> -<p>File contents (and trees, and Other Things we'll get to later) are tied -together into a directory structure by <code>tree</code> objects. These objects contain a -list of records, with one child per record. Each record contains a permissions -field corresponding to the POSIX permissions mask of the object, a type, a -SHA-1 for another object, and a name.</p> -<p>A directory containing only files might be represented as the tree</p> -<pre><code>100644 blob 511542ad6c97b28d720c697f7535897195de3318 config.md -100644 blob 801ddd5ae10d6282bbf36ccefdd0b052972aa8e2 integrate.md -100644 blob 61d28155862607c3d5d049e18c5a6903dba1f85e scratch.md -100644 blob d7a79c144c22775239600b332bfa120775bab341 survival.md -</code></pre> -<p>while a directory with subdirectories would also have some <code>tree</code> children:</p> -<pre><code>040000 tree f57ef2457a551b193779e21a50fb380880574f43 12factor -040000 tree 844697ce99e1ef962657ce7132460ad7a38b7584 authnz -100644 blob 54795f9b774547d554f5068985bbc6df7b128832 cool-urls-can-change.md -040000 tree fc3f39eb5d1a655374385870b8be56b202be7dd8 dev -040000 tree 22cbfb2c1d7b07432ea7706c36b0d6295563c69c devops -040000 tree 0b3e63b4f32c0c3acfbcf6ba28d54af4c2f0d594 git -040000 tree 5914fdcbd34e00e23e52ba8e8bdeba0902941d3f java -040000 tree 346f71a637a4f8933dc754fef02515a8809369c4 mysql -100644 blob b70520badbb8de6a74b84788a7fefe64a432c56d packaging-ideas.md -040000 tree 73ed6572345a368d20271ec5a3ffc2464ac8d270 people -</code></pre> -<h2 id="commits">Commits</h2> -<p>Blobs and trees are sufficient to store arbitrary directory trees in Git, and -you could use them that way, but Git is mostly used as a revision-tracking -system. Revisions and their history are represented by <code>commit</code> objects, which contain:</p> -<pre><code>* The SHA-1 hash of the root `tree` object of the commit, -* Zero or more SHA-1 hashes for parent commits, -* The name and email address of the commit's “author,” -* The name and email address of the commit's “committer,” -* Timestamps representing when the commit was authored and committed, and -* A commit message. -</code></pre> -<p>Commit objects' parent references form a directed acyclic graph; the subgraph -reachable from a specific commit is that commit's <em>history</em>.</p> -<p>When working with Git's user interface, commit parents are given in a -predictable order determined by the <code>git checkout</code> and <code>git merge</code> commands.</p> -<h2 id="tags">Tags</h2> -<p>Git's revision-tracking system supports “tags,” which are stable names for -specific configurations. It also, uniquely, supports a concept called an -“annotated tag,” represented by the <code>tag</code> object type. These annotated tag -objects contain</p> -<pre><code>* The type and SHA-1 hash of another object, -* The name and email address of the person who created the tag, -* A timestamp representing the moment the tag was created, and -* A tag message. -</code></pre> -<h2 id="anonymity">Anonymity</h2> -<p>There's a general theme to Git's object types: no object knows its own name. -Every object only has a name in the context of some containing object, or in -the context of <a href="refs-and-names">Git's refs mechanism</a>, which I'll get to -shortly. This means that the same <code>blob</code> object can be reused for multiple -files (or, more probably, the same file in multiple commits), if they happen -to have the same contents.</p> -<p>This also applies to tag objects, even though their role is part of a system -for providing stable, meaningful names for commits.</p> -<h2 id="examining-objects">Examining objects</h2> -<ul> -<li> -<p><code>git cat-file <type> <sha1></code>: decodes the object <code><sha1></code> and prints its - contents to stdout. This prints the object's contents in their raw form, - which is less than useful for <code>tree</code> objects.</p> -</li> -<li> -<p><code>git cat-file -p <sha1></code>: decodes the object <code><sha1></code> and pretty-prints it. - This pretty-printing stays close to the underlying disk format; it's most - useful for decoding <code>tree</code> objects.</p> -</li> -<li> -<p><code>git show <sha1></code>: decodes the object <code><sha1></code> and formats its contents to - stdout. For blobs, this is identical to what <code>git cat-file blob</code> would do, - but for trees, commits, and tags, the output is reformated to be more - readable.</p> -</li> -</ul> -<h2 id="storage">Storage</h2> -<p>Objects are stored in two places in Git: as “loose objects,” and in “pack -files.” Newly-created objects are initially loose objects, for ease of -manipulation; transferring objects to another repository or running certain -administrative commands can cause them to be placed in pack files for faster -transfer and for smaller storage.</p> -<p>Loose objects are stored directly on the filesystem, in the Git repository's -<code>objects</code> directory. Git takes a two-character prefix off of each object's -SHA-1 hash, and uses that to pick a subdirectory of <code>objects</code> to store the -object in. The remainder of the hash forms the filename. Loose objects are -compressed with zlib, to conserve space, but the resulting directory tree can -still be quite large.</p> -<p>Packed objects are stored together in packed files, which live in the -repository's <code>objects/pack</code> directory. These packed files are both compressed -and delta-encoded, allowing groups of similar objects to be stored very -compactly.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/git/theory-and-practice/objects.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/git/theory-and-practice/objects.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/git/theory-and-practice/refs-and-names.html b/.html/git/theory-and-practice/refs-and-names.html deleted file mode 100644 index fdc56a4..0000000 --- a/.html/git/theory-and-practice/refs-and-names.html +++ /dev/null @@ -1,199 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Refs and Names - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="../">git</a> - - </li> - - <li class="crumb-2 not-last"> - - <a href="./">theory-and-practice</a> - - </li> - - <li class="crumb-3 last"> - - refs-and-names - - </li> - - </ol> - - - - <div id="article"> - <h1 id="refs-and-names">Refs and Names</h1> -<p>Git's <a href="objects">object system</a> stores most of the data for projects tracked in -Git, but only provides SHA-1 hashes. This is basically useless if you want to -make practical use of Git, so Git also has a naming mechanism called “refs” -that provide human-meaningful names for objects.</p> -<p>There are two kinds of refs:</p> -<ul> -<li> -<p>“Normal” refs, which are names that resolve directly to SHA-1 hashes. These - are the vast majority of refs in most repositories.</p> -</li> -<li> -<p>“Symbolic” refs, which are names that resolve to other refs. In most - repositories, only a few of these appear. (Circular references are possible - with symbolic refs. Git will refuse to resolve these.)</p> -</li> -</ul> -<p>Anywhere you could use a SHA-1, you can use a ref instead. Git interprets them -identically, after resolving the ref down to the SHA-1.</p> -<h2 id="namespaces">Namespaces</h2> -<p>Every operation in Git that uses a name of some sort, including branching -(branch names), tagging (tag names), fetching (remote-tracking branch names), -and pushing (many kinds of name), expands those names to refs, using a -namespace convention. The following namespaces are common:</p> -<ul> -<li> -<p><code>refs/heads/NAME</code>: branches. The branch name is the ref name with - <code>refs/heads/</code> removed. Names generally point to commits.</p> -</li> -<li> -<p><code>refs/remotes/REMOTE/NAME</code>: “remote-tracking” branches. These are maintained - in tandem by <code>git remote</code> and <code>git fetch</code>, to cache the state of other - repositories. Names generally point to commits.</p> -</li> -<li> -<p><code>refs/tags/NAME</code>: tags. The tag name is the ref name with <code>refs/heads/</code> - removed. Names generally point to commits or tag objects.</p> -</li> -<li> -<p><code>refs/bisect/STATE</code>: <code>git bisect</code> markers for known-good and known-bad - revisions, from which the rest of the bisect state can be derived.</p> -</li> -</ul> -<p>There are also a few special refs directly in the <code>refs/</code> namespace, most -notably:</p> -<ul> -<li><code>refs/stash</code>: The most recent stash entry, as maintained by <code>git stash</code>. - (Other stash entries are maintained by a separate system.) Names generally - point to commits.</li> -</ul> -<p>Tools can invent new refs for their own purposes, or manipulate existing refs; -the convention is that tools that use refs (which is, as I said, most of them) -respect the state of the ref as if they'd created that state themselves, -rather than sanity-checking the ref before using it.</p> -<h2 id="special-refs">Special refs</h2> -<p>There are a handful of special refs used by Git commands for their own -operation. These refs do <em>not</em> begin with <code>refs/</code>:</p> -<ul> -<li> -<p><code>HEAD</code>: the “current” commit for most operations. This is set when checking - out a commit, and many revision-related commands default to <code>HEAD</code> if not - given a revision to operate on. <code>HEAD</code> can either be a symbolic ref - (pointing to a branch ref) or a normal ref (pointing directly to a commit), - and is very frequently a symbolic ref.</p> -</li> -<li> -<p><code>MERGE_HEAD</code>: during a merge, <code>MERGE_HEAD</code> resolves to the commit whose - history is being merged.</p> -</li> -<li> -<p><code>ORIG_HEAD</code>: set by operations that change <code>HEAD</code> in potentially destructive - ways by resolving <code>HEAD</code> before making the change.</p> -</li> -<li> -<p><code>CHERRY_PICK_HEAD</code> is set during <code>git cherry-pick</code> to the commit whose - changes are being copied.</p> -</li> -<li> -<p><code>FETCH_HEAD</code> is set by the forms of <code>git fetch</code> that fetch a single ref, and - points to the commit the fetched ref pointed to.</p> -</li> -</ul> -<h2 id="examining-and-manipulating-refs">Examining and manipulating refs</h2> -<p>The <code>git show-ref</code> command will list the refs in namespaces under <code>refs</code> in -your repository, printing the SHA-1 hashes they resolve to. Pass <code>--head</code> to -also include <code>HEAD</code>.</p> -<p>The following commands can be used to manipulate refs directly:</p> -<ul> -<li> -<p><code>git update-ref <ref> <sha1></code> forcibly sets <code><ref></code> to the passed <code><sha1></code>.</p> -</li> -<li> -<p><code>git update-ref -d <ref></code> deletes a ref.</p> -</li> -<li> -<p><code>git symbolic-ref <ref></code> prints the target of <code><ref></code>, if <code><ref></code> is a - symbolic ref. (It will fail with an error message for normal refs.)</p> -</li> -<li> -<p><code>git symbolic-ref <ref> <target></code> forcibly makes <code><ref></code> a symbolic ref - pointing to <code><target></code>.</p> -</li> -</ul> -<p>Additionally, you can see what ref a given name resolves to using <code>git -rev-parse --symbolic-full-name <name></code> or <code>git show-ref <name></code>.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/git/theory-and-practice/refs-and-names.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/git/theory-and-practice/refs-and-names.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/gossamer/_list.html b/.html/gossamer/_list.html deleted file mode 100644 index 55c8e0f..0000000 --- a/.html/gossamer/_list.html +++ /dev/null @@ -1,88 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /gossamer - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">gossamer</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /gossamer</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="mistakes">Design Mistakes</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/gossamer">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/gossamer/index.html b/.html/gossamer/index.html deleted file mode 100644 index 66fe858..0000000 --- a/.html/gossamer/index.html +++ /dev/null @@ -1,463 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Gossamer: A Decentralized Status-Sharing Network - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 last"> - - gossamer - - </li> - - </ol> - - - - <div id="article"> - <h1 id="gossamer-a-decentralized-status-sharing-network">Gossamer: A Decentralized Status-Sharing Network</h1> -<p>Twitter's pretty great. The short format encourages brief, pithy remarks, and -the default assumption of visibility makes it super easy to pitch in on a -conversation, or to find new people to listen to. Unfortunately, Twitter is a -centralized system: one Bay-area company in the United States controls and -mediates <em>all</em> Twitter interactions.</p> -<p>From all appearances, Twitter, Inc. is relatively benign, as social media -corporations go. There are few reports of censorship, and while their -response to abuse of the Twitter network has not been consistently awesome, -they can be made to listen. However, there exists the capacity for Twitter, -Inc. to subvert the entire Twitter system, either voluntarily or at the -behest of governments around the world.</p> -<p>(Just ask Turkish people. Or the participants in the Arab Spring.)</p> -<p>Gossamer is a Twitter-alike system, designed from the ground up to have no -central authority. It resists censorship, enables individual participants to -control their own data, and allows anyone at all to integrate new software -into the Gossamer network.</p> -<p>Gossamer does not exist, but if it did, the following notes describe what it -might look like, and the factors to consider when implementing Gossamer as -software. I have made <a href="mistakes">fatal mistakes</a> while writing it; I have not -rushed to build it specifically because Twitter, Gossamer's model, is so -deeply woven into so many peoples' lives. A successor must make fewer -mistakes, not merely different mistakes, and certainly not more mistakes.</p> -<p>The following is loosely inspired by <a href="http://www.mememotes.com/meme_motes/2005/02/rumor_monger.html">Rumor -Monger</a>, at -“whole world” scale.</p> -<h2 id="design-goals">Design Goals</h2> -<ul> -<li> -<p>Users must be in control of their own privacy and identity at all times. - (This is a major failing with Diaspora, which limits access to personal - ownership of data by being hard to run.)</p> -</li> -<li> -<p>Users must be able to communicate without the consent or support of an - intermediate authority. Short of being completely offline, Gossamer should - be resilient to infrastructural damage.</p> -</li> -<li> -<p>Any functional communication system <em>will</em> be used for illicit purposes. - This is an unavoidable consequence of being usable for legitimate purposes - without a central authority. Rather than revealing illicit conversations, - Gossamer should do what it can to preserve the anonymity and privacy of - legitimate ones.</p> -</li> -<li> -<p>All nodes are as equal as possible. The node <em>I</em> use is not more - authoritative for messages from me than any other node. You can hear my - words from anyone who has heard my words, and I can hear yours from anyone - who has heard your words, so long as some variety of authenticity and - privacy are maintained.</p> -</li> -<li> -<p>If an identity's secrets are removed, a node should contain no data that - correlates the owner with his or her Gossamer identities. Relaying and - authoring must be as indistinguishable as possible, to limit the utility of - traffic analysis.</p> -</li> -</ul> -<h2 id="public-and-private-information">Public and Private Information</h2> -<p>Every piece of data Gossamer uses, either internally or to communicate with -other ndoes, is classified as either <em>public</em> or <em>private</em>. Public -information can be communicated to other nodes, and is assumed to be safe if -recovered out of band. Private information includes anything which may be -used to associate a Gossamer identity with the person who controls it, except -as noted below.</p> -<p>Gossamer must ensure users understand what information that they provide will -be made public, and what will be kept private, so that they can better decide -what, if anything, to share and so that they can better make decisions about -their own safety and comfort against abusive parties.</p> -<p>Internally, Gossamer <em>always</em> stores private information encrypted, and -<em>never</em> transmits it to another node. Gossamer <em>must</em> provide a tool to -safely obliterate private data.</p> -<h3 id="public-information">Public Information</h3> -<p>Details on the role of each piece of information are covered below.</p> -<ul> -<li> -<p>Public status updates, obviously. Gossamer exists to permit users to easily - share short messages with one another.</p> -</li> -<li> -<p>The opaque form of a user's incoming and outgoing private messages.</p> -</li> -<li> -<p>The users' identities' public keys. (But not their relationship to one - another.)</p> -</li> -<li> -<p>Any information the user places in their profile. (This implies that - profiles <em>must not</em> be auto-populated from, for example, the user's address - book.)</p> -</li> -<li> -<p>The set of identities verified by the user's identity.</p> -</li> -</ul> -<p>Any other information Gossamer retains <em>must</em> be private.</p> -<h2 id="republishing">Republishing</h2> -<p>Gossamer is built on the assumption that every participant is willing to act -as a relay for every other participant. This is a complicated assumption at -the human layer.</p> -<p>Inevitably, someone will use the Gossamer network to communicate something -morally repugnant or deeply illegal: the Silk Road guy, for example, got done -for trying to contract someone to commit murder. Every Gossamer node is -complicit in delivering those messages to the rest of the network, whether -they're in the clear (status updates) or not (private messages). It's unclear -how this interacts with the various legal frameworks, moral codes, and other -social constructs throughout the world, and it's ethically troubling to put -users in that position by default.</p> -<p>The strong alternative, that each node only relay content with the -controlling user's explicit and ongoing consent, is also troubling: it limits -the Gossamer network's ability to deliver messages <em>at all</em>, and exposes -information about which identities each node's owner considers interesting -and publishable.</p> -<p>I don't have an obvious resolution to this. Gossamer's underlying protocol -relies on randomly-selected nodes being more likely to propagate a message -than to ignore it, because this helps make Gossamer resilient to hostile -users, nosy intelligence agencies, and others who believe communication must -be restrictable. On the other hand, I'd like not to put a user in Taiwan at -risk of legal or social reprisals because a total stranger in Canada decided -to post something vile.</p> -<p>(This is one of the reasons I haven't <em>built</em> the damn thing yet. Besides -being A Lot Of Code, there's no way to shut off Gossamer once more than one -node exists, and I want to be sure I've thought through what I'm doing before -creating a prototype.)</p> -<h2 id="identity-in-the-gossamer-network">Identity in the Gossamer Network</h2> -<p>Every Gossamer <em>message</em> carries with it an <em>identity</em>. Gossamer identities -are backed by public-key cryptography. However, unlike traditional public key -systems such as GPG, Gossamer identities provide <em>continuity</em>, rather than -<em>authenticity</em>: two Gossamer messages signed by the same key are from the -same identity, but there is no inherent guarantee that that identity is -legitimate.</p> -<p>Gossamer maintains relationships between identities to allow users to -<em>verify</em> the identities of one another, and to publish attestations of that -to other Gossamer nodes. From this, Gossamer can recover much of GPG's “web -of trust.”</p> -<p><strong>TODO</strong>: revocation of identities, revocation of verifications. Both are -important; novice users are likely to verify people poorly, and there should -be a recovery path less drastic than GPG's “you swore it, you're stuck with -it” model.</p> -<p>Gossamer encourages users to create additional identities as needed to, for -example, support the separation of work and home conversations, or to provide -anonymity when discussing reputationally-hazardous topics. Identities are not -correlated by the Gossamer codebase.</p> -<p>Each identity can optionally include a <em>profile</em>: a block of data describing -the person behind the identity. The contents of a profile are chosen by the -person holding the private key for an identity, and the profile is attached -to every new message created with the corresponding identity. A user can -update their profile at will; potentially, every message can be sent with a -distinct profile. Gossamer software treats the profile it's seen with the -highest timestamp as authoritative, retroactively applying it to old messages.</p> -<h3 id="multiple-devices-and-key-security">Multiple Devices and Key Security</h3> -<p>A Gossamer identity is entirely contained in its private key. An identity's -key must be stored safely, either using the host operating system's key -management facilities or using a carefully-designed key store. Keys must not -hit long-term storage unprotected; this may involve careful integration with -the underlying OS's memory management facilities to avoid, eg., placing -identities in swap. This is <em>necessary</em> to protect users from having their -identities recovered against their will via, for example, hard drive -forensics.</p> -<p>Gossamer allows keys to be exported into password-encrypted archive files, -which can be loaded into other Gossamer applications to allow them to share -the same identity.</p> -<p><strong>GOSSAMER MUST TREAT THESE FILES WITH EXTREME CARE, BECAUSE USERS PROBABLY -WON'T</strong>. Identity keys protect the user's Gossamer identity, but they <em>also</em> -protect the user's private messages (see below) and other potentially -identifying data. The export format must be designed to be as resilient as -possible, and Gossamer's software must take care to ensure that “used” -identity files are <em>automatically</em> destroyed safely wherever possible and to -discourage users from following practices that weaken their own safety -unknowingly.</p> -<p>Exported identity files are intrinsically vulnerable to offline brute-force -attacks; once obtained, an attacker can try any of the worryingly common -passwords at will, and can easily validate a password by using the recovered -keys to regenerate some known fact about the original, such as a verification -or a message signature. This implies that exported identities <em>must</em> use a -key derivation system which has a high computational cost and which is -believed to be resilient to, for example, GPU-accelerated cracking.</p> -<p>Secure deletion is a Hard Problem; where possible, Gossamer must use -operating system-provided facilities for securely destroying files.</p> -<h2 id="status-messages">Status Messages</h2> -<p>Status messages are messages visible to any interested Gossamer users. These -are the primary purpose of Gossamer. Each contains up to 140 Unicode -characters, a markup section allowing Gossamer to attach URLs and metadata -(including Gossamer locators) to the text, and an attachments section -carrying arbitrary MIME blobs of limited total size.</p> -<p>All three sections are canonicalized (<strong>TODO</strong>: how?) and signed by the -publishing identity's private key. The public key, the identity's most recent -profile, and the signed status message are combined into a single Gossamer -message and injected into the user's Gossamer node exactly as if it had -arrived from another node.</p> -<p>Each Gossamer node maintains a <em>follow list</em> of identities whose messages the -user is interested in seeing. When Gossamer receives a novel status message -during a gossip exchange, it displays it to the user if and only if its -identity is on the node's follow list. Otherwise, the message is not -displayed, but will be shared onwards with other nodes. In this way, every -Gossamer node acts as a relay for every other Gossamer node.</p> -<p>If Gossamer receives a message signed by an identity it has seen attestations -for, it attaches those attestations to the message before delivering them -onwards. In this way, users' verifications of one another's identity spread -through the network organically.</p> -<h2 id="private-messages">Private Messages</h2> -<p>Gossamer can optionally encrypt messages, allowing users to send one another -private messages. These messages are carried over the Gossamer network as -normal, but only nodes holding the appropriate identity key can decrypt them -and display them to the user. (At any given time, most Gossamer nodes hold -many private messages they cannot decrypt.)</p> -<p>Private messages <em>do not</em> carry the author's identity or full profile in the -clear. The author's bare identity is included in the encrypted part of the -message, to allow the intended recipient to identify the sender.</p> -<p><strong>TODO</strong>: sign-then-encrypt, or encrypt-then-sign? If sign-then-encrypt, are -private messages exempted from the “drop broken messages” rule above?</p> -<h2 id="following-users">Following Users</h2> -<p>Each Gossamer node maintains a database of <em>followed</em> identities. (This may -or may not include the owner's own identity.) Any message stored in the node -published by an identity in this database will be shown to the user in a -timeline-esque view.</p> -<p>Gossamer's follow list is <em>purely local</em>, and is not shared between nodes -even if they have identities in common. The follow list is additionally -stored encrypted using the node's identities (any one identity is sufficient -to recover the list), to ensure that the follow list is not easily available -to others without the node owner's permission.</p> -<p>Exercises such as <a href="http://kieranhealy.org/blog/archives/2013/06/09/using-metadata-to-find-paul-revere/">Finding Paul Revere</a> -have shown that the collection of graph edges showing who communicates with -whom can often be sufficient to map identities into people. Gossamer attempts -to restrict access to this data, believing it is not the network's place to -know who follows who.</p> -<h2 id="verified-identities">Verified Identities</h2> -<p>Gossamer allows identities to sign one anothers' public keys. These -signatures form <em>verifications</em>. Gossamer considers an identity <em>verified</em> if -any of the following hold:</p> -<ul> -<li> -<p>Gossamer has access to the identity key for the identity itself.</p> -</li> -<li> -<p>Gossamer has access to the identity key for at least one of the identity's - verifications.</p> -</li> -<li> -<p>The identity is signed by at least three (todo: or however many, I didn't - do the arithmetic yet) verified identities.</p> -</li> -</ul> -<p>Verified identities are marked in the user interface to make it obvious to -the user whether a message is from a known friend or from an unknown identity.</p> -<p>Gossamer allows users to sign new verifications for any identity they have -seen. These verifications are initially stored locally, but will be published -as messages transit the node as described below. Verification is a <em>public</em> -fact: everyone can see which identities have verified which other identities. -This is a potentially very powerful tool for reassociating identities with -real-world people; Gossamer <em>must</em> make this clear to users.</p> -<p>(I'm pretty sure you could find me, personally, just by watching whose -identities I verify.)</p> -<p>Each Gossamer node maintains a database of every verification it has ever -seen or generated. If the node receives a message from an identity that -appears in the verification database, and if the message is under some total -size, Gossamer appends verifications from its database to the message before -reinjecting it into the network. This allows verifications to propagate -through</p> -<h2 id="blocking-users">Blocking Users</h2> -<p>Any social network will attract hostile users who wish to disrupt the network -or abuse its participants. Users <em>must</em> be able to filter out these users, -and must not provide too much feedback to blocked users that could otherwise -be used to circumvent blocks.</p> -<p>Each Gossamer node maintains a database of blocked identities. Any message -from an identity in this database, or from an identity that is verified by -three or more identities in this database, will automatically be filtered out -from display. (Additionally, transitively-blocked users will automatically be -added to the block database. Blocking is contagious.) (<strong>TODO</strong>: should -Gossamer <em>drop</em> blocked messages? How does that interact with the inevitable -“shared blocklist” systems that arise in any social network?)</p> -<p>As with the follow list, the block database is encrypted using the node's -identities.</p> -<p>Gossamer encourages users to create new identities as often as they see fit -and attempts to separate identities from one another as much as possible. -This is fundamentally incompatible with strong blocking. It will <em>always</em> be -possible for a newly-created identity to deliver at least one message before -being blocked. <em>This is a major design problem</em>; advice encouraged.</p> -<h2 id="gossamer-network-primitives">Gossamer Network Primitives</h2> -<p>The Gossamer network is built around a gossip protocol, wherein <em>nodes</em> -connect to one another periodically to exchange <em>messages</em> with one another. -Connections occur over the existing IP internet infrastructure, traversing -NAT networks where possible to ensure that users on residential and corporate -networks can still participate.</p> -<p>Gossamer bootstraps its network using a number of paths:</p> -<ul> -<li> -<p>Gossamer nodes in the same broadcast domain discover one another using UDP - broadcasts as well as Bonjour/mDNS.</p> -</li> -<li> -<p>Gossamer can generate <em>locator</em> strings, which can be shared “out of band” - via email, SMS messages, Twitter, graffiti, etc.</p> -</li> -<li> -<p>Gossamer nodes share knowledge of nodes whenever they exchange messages, to - allow the Gossamer network to recover from lost nodes and to permit nodes - to remain on the network as “known” nodes are lost to outages and entropy.</p> -</li> -</ul> -<h3 id="locators">Locators</h3> -<p>A Gossamer <em>locator</em> is a URL in the <code>g</code> scheme, carrying an encoding of one -or more network addresses as well as an encoding of one or more identities -(see below). Gossamer's software attempts to determine an appropriate -identifier for any identities it holds based on the host computer's network -configuration, taking into account issues like NAT traversal wherever -possible.</p> -<p><strong>TODO</strong>: Gossamer and uPNP, what do locators <em>look</em> like?</p> -<p>When presented with an identifier, Gossamer offers to <em>follow</em> the identities -it contains, and uses the <em>nodes</em> whose addresses it contains to connect to -the Gossamer network. This allows new clients to bootstrap into Gossamer, and -provides an easy way for users to exchange Gossamer identities to connect to -one another later.</p> -<p>(Clever readers will note that the address list is actually independent of -the identity list.)</p> -<h3 id="gossip">Gossip</h3> -<p>Each Gossamer node maintains a pair of “freshness” databases, associating -some information with a freshness score (expressed as an integer). One -freshness database holds the addresses of known Gossamer nodes, and another -holds Gossamer messages.</p> -<p>Whenever two Gossamer nodes interact, each sends the other a Gossamer node -from its current node database, and a message from its message database. When -selecting an item to send for either category, Gossamer uses a random -selection that weights towards items with a higher “freshness” score. -(<strong>TODO</strong>: how?)</p> -<p>When sending a fact, if the receiving node already knows the fact, both nodes -decrement that fact's freshness by one. If the receiving node <em>does not</em> -already know the fact, the sending node leaves its freshness unaltered, and -the receiving node sets its freshness to the freshest possible value. This -system encourages nodes to exchange “fresh” facts, then cease exchanging them -as the network becomes aware of them.</p> -<p>During each exchange, Gossamer nodes send each other one Gossamer node -address, and one Gossamer message. Both nodes adjust their freshness -databases, as above.</p> -<p>If fact exchange fails while communicating with a Gossamer node, both nodes -decrement their peer's freshness. Unreliable nodes can continue to initiate -connections to other nodes, but will rarely be contacted by other Gossamer -nodes.</p> -<p><strong>TODO</strong>: How do we avoid DDOSing brand-new gossamer nodes with the full -might of Gossamer's network?</p> -<p><strong>TODO</strong>: Can we reuse Bittorrent's DHT system (BEP-5) to avoid having every -node know the full network topology?</p> -<p><strong>TODO</strong>: Are node-to-node exchanges encrypted? If so, why and how?</p> -<h3 id="authenticity">Authenticity</h3> -<p>Gossamer node addresses are not authenticated. Gossamer relies on freshness -to avoid delivering excess traffic to systems not participating in the -Gossamer network. (<strong>TODO</strong>: this is a shit system for avoiding DDOS, though.)</p> -<p>Gossamer messages <em>are</em> partially authenticated: each carries with it a -public key, and a signature. If the signature cannot be verified with the -included public key, it <em>must</em> be discarded immediately and it <em>must not</em> be -propagated to other nodes. The node delivering the message <em>may</em> also be -penalized by having its freshness reduced in the receiving node's database.</p> -<h3 id="gossip-triggers">Gossip Triggers</h3> -<p>Gossamer triggers a new Gossip exchange under the following circumstances:</p> -<ul> -<li> -<p>15 seconds, plus a random jitter between zero and 15 more seconds, elapse - since the last exchange attempt.</p> -</li> -<li> -<p>Gossamer completes an exchange wherein it learned a new fact from another - node.</p> -</li> -<li> -<p>A user injects a fact into Gossamer directly.</p> -</li> -</ul> -<p>Gossamer exchanges that fail, or that deliver only already-known facts, do -not trigger further exchanges immediately.</p> -<p><strong>TODO</strong>: how do we prevent Gossamer from attempting to start an unbounded -number of exchanges at the same time?</p> -<h3 id="size">Size</h3> -<p>Gossamer must not exhaust the user's disk. Gossamer discards <em>extremely</em> -un-fresh messages, attempting to keep the on-disk size of the message -database to under 10% of the total local storage, or under a -user-configurable threshold.</p> -<p>Gossamer rejects over-large messages. Public messages carry with them the -author's profile and a potentially large collection of verifications. -Messages over some size (<strong>TODO</strong> what size?) are discarded on receipt -without being stored, and the message exchange is considered to have failed.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/gossamer/index.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/gossamer/index.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/gossamer/mistakes.html b/.html/gossamer/mistakes.html deleted file mode 100644 index d7632f7..0000000 --- a/.html/gossamer/mistakes.html +++ /dev/null @@ -1,154 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Design Mistakes - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">gossamer</a> - - </li> - - <li class="crumb-2 last"> - - mistakes - - </li> - - </ol> - - - - <div id="article"> - <h1 id="design-mistakes">Design Mistakes</h1> -<h2 id="is-gossamer-up">Is Gossamer Up?</h2> -<p><a href="https://twitter.com/megtastique">@megtastique</a> points out that two factors -doom the whole design:</p> -<ol> -<li> -<p>There's no way to remove content from Gossamer once it's published, and</p> -</li> -<li> -<p>Gossamer can anonymously share images.</p> -</li> -</ol> -<p>Combined, these make Gossamer the <em>perfect</em> vehicle for revenge porn and -other gendered, sexually-loaded network abuse.</p> -<p>This alone is enough to doom the design, as written: even restricting the -size of messages to the single kilobyte range still makes it trivial to -irrevocably disseminate <em>links</em> to similar content.</p> -<h2 id="protected-feeds-who-needs-those">Protected Feeds? Who Needs Those?</h2> -<p>Gossamer's design does not carry forward an important Twitter feature: the -protected feed. In brief, protected feeds allow people to be choosy about who -reads their status updates, without necessarily having to pick and choose who -gets to read them on a message by message basis.</p> -<p>This is an important privacy control for people who wish to engage with -people they know without necessarily disclosing their whereabouts and -activities to the world at large. In particular, it's important to vulnerable -people because it allows them to create their own safe spaces.</p> -<p>Protected feeds are not mere technology, either. Protected feeds carry with -them social expectations: Twitter clients often either refuse to copy text -from a protected feed, or present a warning when the user tries to copy text, -which acts as a very cheap and, apparently, quite effective brake on the -casual re-sharing that Twitter encourages for public feeds.</p> -<h2 id="ddos-as-a-service">DDOS As A Service</h2> -<p>Gossamer's network protocol converges towards a total graph, where every node -knows how to connect to every other node, and new information (new posts) -rapidly push out to every single node.</p> -<p>If you've ever been privy to the Twitter “firehose” feed, you'll understand -why this is a drastic mistake. Even a moderately successful social network -sees on the order of millions of messages a day. Delivering <em>all</em> of this -directly to <em>every</em> node <em>all</em> of the time would rapidly drown users in -bandwidth charges and render their internet connections completely unusable.</p> -<p>Gossamer's design also has no concept of “quiet” periods: every fifteen to -thirty seconds, rain or shine, every node is supposed to wake up and exchange -data with some other node, regardless of how long it's been since either node -in the exchange has seen new data. This very effectively ensures that -Gossamer will continue to flood nodes with traffic at all times; the only way -to halt the flood is to shut off the Gossamer client.</p> -<h2 id="passive-nodes-matter">Passive Nodes Matter</h2> -<p>It's impractical to run an inbound data service on a mobile device. Mobile -devices are, by and large, not addressable or reachable by the internet at -large.</p> -<p>Mobile devices also provide a huge proportion of Twitter's content: the -ability to rapidly post photos, location tags, and short text while away from -desks, laptops, and formal internet connections is a huge boon for ad-hoc -social organization. You can invite someone to the pub from your phone, from -in front of the pub.</p> -<p>(This interacts ... poorly with the DDOS point, above.)</p> -<h2 id="traffic-analysis">Traffic Analysis</h2> -<p>When a user enters a new status update or sends a new private message, their -Gossamer node immediately forwards it to at least one other node to inject it -into the network. This makes unencrypted Gossamer relatively vulnerable to -traffic analysis for correlating Gossamer identities with human beings.</p> -<p>Someone at a network “pinch point” -- an ISP, or a coffee shop wifi router -- -can monitor Gossamer traffic entering and exiting nodes on their network and -easily identify which nodes originated which messages, and thus which nodes -have access to which identities. This seriously compromises the effectiveness -of Gossamer's decentralized, self-certifying identities.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/gossamer/mistakes.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/gossamer/mistakes.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/gpg/_list.html b/.html/gpg/_list.html deleted file mode 100644 index 8f54701..0000000 --- a/.html/gpg/_list.html +++ /dev/null @@ -1,92 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /gpg - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">gpg</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /gpg</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="cool">GPG Is Pretty Cool</a></li> - - <li><a href="terrible">GPG Is Terrible</a></li> - - <li><a href="keys">GPG Keys</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/gpg">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/gpg/cool.html b/.html/gpg/cool.html deleted file mode 100644 index 528ce0c..0000000 --- a/.html/gpg/cool.html +++ /dev/null @@ -1,146 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - GPG Is Pretty Cool - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">gpg</a> - - </li> - - <li class="crumb-2 last"> - - cool - - </li> - - </ol> - - - - <div id="article"> - <h1 id="gpg-is-pretty-cool">GPG Is Pretty Cool</h1> -<p>The GPG software suite is a pretty elegant cryptosystem. It provides:</p> -<ul> -<li> -<p>A standard, well-maintained set of tools for creating and storing keys, and - associating them with identities</p> -</li> -<li> -<p>A suite of reliable tools for encrypting, signing, decrypting, and - verifying data that can be easily assembled into any combination of - integrity checks, authenticity checks, and privacy management</p> -</li> -<li> -<p>A key distribution network that does not rely on hierarchal authority and - that can be bootstrapped from scratch quickly and easily</p> -</li> -</ul> -<p>While GPG <a href="terrible">sucks in a number of important ways</a>, it's also the best -tool we have right now for restoring privacy to private correspondance over -the internet.</p> -<h2 id="code-signing">Code Signing</h2> -<p>Pretty much every Linux distribution relies on GPG for code signing. Rather -than using GPG's web-of-trust model for key distribution, however, code -signing with GPG usually creates a hierarchal PKI so that the root keys can -be shipped with the operating system.</p> -<p>This works shockingly well, and support for GPG is extremely well integrated -into common package management systems such as apt and yum.</p> -<h2 id="source-control">Source Control</h2> -<p>Which is basically code signing, admittedly, but even Git's support for GPG -is basically great. Tools like Fossil embed it even deeper, and work quite -well.</p> -<h2 id="email">Email</h2> -<p>GPG's integration with email is surprisingly clever, follows a number of -long-standing best practices for extending email, and does a <em>very</em> good job -of providing some guarantees that make sense in a not-terribly-long-ago view -of email as a communications medium. In particular, if</p> -<ul> -<li>who you talk to is not a secret, and</li> -<li>what, broadly, you are talking about is not a secret, but</li> -<li>the specifics of the discussion <em>are</em> a secret, and</li> -<li>all participants are using GPG on their own mailers</li> -</ul> -<p>then GPG works brilliantly and modern GPG integration is very effective.</p> -<p>These assumptions pretty accurately reflect the majority of email use up -through the late 90s and early 2000s: technical or personal correspondence -between known acquaintences.</p> -<p>The internet has moved on from email for casual correspondence, but that -doesn't invalidate the elegance of GPG's integration for GPG users.</p> -<h2 id="distributed-verification">Distributed Verification</h2> -<p>Even though GPG's trust model has some serious privacy costs and concerns, it -works as a great proof of concept for CA-free identity management. That's -huge: centralized CAs have even more onerous costs and worse risks than GPG's -trust network, while offering less transparency to help offset those costs.</p> -<p>Others have written some pretty interesting things on how to improve GPG's -trust model and make it less succeptible to errors or key leaks by -small-to-middling numbers of participants. <a href="https://lists.torproject.org/pipermail/tor-talk/2013-September/030235.html">This -post</a> -to tor-talk last year is probably the most complete.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/gpg/cool.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/gpg/cool.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/gpg/index.html b/.html/gpg/index.html deleted file mode 100644 index 8f54701..0000000 --- a/.html/gpg/index.html +++ /dev/null @@ -1,92 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /gpg - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">gpg</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /gpg</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="cool">GPG Is Pretty Cool</a></li> - - <li><a href="terrible">GPG Is Terrible</a></li> - - <li><a href="keys">GPG Keys</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/gpg">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/gpg/keys.html b/.html/gpg/keys.html deleted file mode 100644 index 9fe112b..0000000 --- a/.html/gpg/keys.html +++ /dev/null @@ -1,271 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - GPG Keys - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">gpg</a> - - </li> - - <li class="crumb-2 last"> - - keys - - </li> - - </ol> - - - - <div id="article"> - <h1 id="gpg-keys">GPG Keys</h1> -<p>If you've read <a href="terrible">GPG Is Terrible</a> and <a href="cool">GPG Is Pretty Cool</a>, -and their references, and for some reason still feel the need to use GPG, my -key fingerprint is <code>77BD C4F1 6EFD 607E 85AA B639 5023 2991 F10D FFD0</code>. The -key itself is below.</p> -<pre><code>-----BEGIN PGP PUBLIC KEY BLOCK----- - -mQENBFOWElgBCADSFR0SmdJX5yOFjejxTpjdyc2UwjglM4WqFNne7C9rYkbLGj8U -y6aVdLop4kFdiZrtuAyJrZnKawZglMar6erBgoNXe3vrbEzopPI1Uev/kY7UHSR+ -dA8EYw50/FOvDYlrJxntvIEfNYskIvhS+c8Y0HSrK9VnKfkfi7hYJP+93sqP/4Lz -oCnCWQCJSOaOdpora241/bsEU7w8MCiexCdm2NaPc6q445K5XAO5CoLkTwcJxJHM -xbPH7prSgqdDz5Y00hUDqm+ByLCMVyAFu4/6sEMWZMaOIIEh0a/kpD+xJVkXKszh -5SsLNZ5oADj9DWHvFoemj1gOixzYlEMdqL3PABEBAAG0KU93ZW4gSmFjb2Jzb24g -PG93ZW4uamFjb2Jzb25AZ3JpbW9pcmUuY2E+iQEcBBMBCgAGBQJT8kqMAAoJENKx -mZ8cUdIj7jIIAIamt/VdAr9BB835knMQ48QQaqQr1KrpvL8QCMWen/lcgMBz5FSM -ZmPImroQKakjKqNbJV5OLKOZGQxNNGxOSP6WSbUEDCiP1J4XddTCogPH2ePL0g+y -YjoaO24uY6VIjNaY9plf8DQqD3gkcZBX0QjVT+q3MxvhFG8Ox4S+kXDV5qYXDLiB -PZM1Jv1PDY777Ml6J1Zv4z5oveaKVZfCjdJ7h00QQ+nnKBWIeE4rqqNwtCnM0SoX -T5zlogZKdCK9mTFzmTMaVmASjYO7xWhIy3bSy2Ke/cyCup2zdc/IhLJio4D/2HRm -DURsMj8MhIJN4eJymtGw2VQYB300k0cSUWuJAUAEEwEKACoCGwMFCwkIBwMFFQoJ -CAsFFgIDAQACHgECF4ACGQEFAlR9+1UFCQHjt30ACgkQUCMpkfEN/9AnYwgAju6I -dWaWEdujxXJS+d2I2bsfraoxu0wlltlX4Z5MDh8h2OAV90fQKJTXx4mSzYgmGL0v -/2RMnBciSQWskmpHMBGY+dLi0uIb5WOeqttUoLMyq/L7ENhCksKgI/g6RqWCM7+W -M6LjA09GcCLZMSpZ2xpDyjibtJh4WaO+h+JT6O0UonhMszGgeUf4UH5zIvmkA+Su -b4mG8tQtBwqEjikXhMsOa27dWj+f+c0Oth3WwFBTfbucw0aSkwDC3L9geyKInJGZ -W2IC5f7gXJ8MID/aDKNrAOLRGJpqv7d+LZhtyNx6MUh+mNmwplYytEmqdmz2fWss -l+8arRPUbjA5QdQlH4kCHAQSAQIABgUCU5nlmQAKCRAaK96qaP2zTPShEACNaECa -WC4qUT+5SJsVPU3skeWd+jp7FVk1P2+IU6pIbB65F04Q+vDbYPR6WVjtuqoxLd5D -QYcTsUlOE7k1LQlel3FU/8PH0QfhOw6/VMnFpprYns9QISQVuvQUHgl6kWMh2CiJ -cBB0XQnd7DwRfdR79sOr6UHNBZGYbcKjgq67qq2H7oGuBfzAihYx0ZaJPBGb2QC9 -Efy2xYnEKWHaeI5FpjjcaZKftAe7kDL9T0zMdEicH5txbYNDVB5gBNyhhHakBakl -phb2rnnbtwsk4pEaPYq/eNxwv/VcJypySlRk+eCCHDlWUhbgRlmr4600EdFNnmCF -y3rA4nYX9kLu/JYzBwj4VCNkJYDyTCdSCnv8zoLJ/bBFWUEmX0Pvz6gIEQ2Tr5D6 -4t3dn4fIHcdDXAyZb4xj0jJoG+ebDp9uezm1/KFQo7N45yYvWXZGhM515YQZ09nU -KTgjE1v5H5NThEsw8pn0a6mi+mcHq/V8Au5/EQwh/Ch2KEquQ/MSjCsGOoJOgQTc -+XrzmhUkd2ukxVPXvXE8G+/khT+RRGs6Fttc7b8op/TuTdZCKK+xskyAzmAfc7BB -RbxVckQs77B3sFJgzgFpxNOuHwVkJN0ZQSTe84DVN80b8JGXrnuCf9EYQiAF4Vw9 -JVorLLif999+JZ3wlGqDTWqeUtElzZfP38ftmYkBHAQQAQIABgUCVMx03gAKCRBg -rwNo53dYqIvXB/9jGFivwG+s0tMdYB1HJ6OdxRu5cOnBRZNwxJP14VQ0dQlW+Ypv -cQu0iVb0hA3L/80fw4rx1ul5yrxS6chUUcC1Kz7hIapWa2uMluUZYAfvGTutZ9g1 -uRJzW8+DkMYNowc4wpuprAZqxhcMbjcSomhROBphl7o8kcrn2eNbCIkV/oEE/8Yi -e01vrDaBsqbH0PcHlP0WK05dswF7VYZLOa7RzUnTXTRRewE5XwzOgBDMWigRWlJv -wtcgAXUTTzH68G8gmN5TZVw5MMwrKOSfAOLQ0H+R/sdfK/zqLUrTkt//Rdyedh4s -urNJxtbFgHhv3izZx4gUBkmZzgKbPXqhGfqjtCZPd2VuIEphY29ic29uIDxhbmdy -eWJhbGRndXlAZ21haWwuY29tPokBHAQTAQoABgUCU/JKmAAKCRDSsZmfHFHSI2n1 -CACDZwumtVBJ6eGS6rySvj+lgH0HDX0KpdL/I0a3N7a/G/xGgJLBdn/vBaSNnvr8 -jAbdUXKMTMbd3Y0VxDFFS0u9lbiryjaljCaNFydXK+auY4HzE0PoOfTb5iPMyfXt -O3e+CmyAfhP5Q5Tz+HP8gWhi1IvC1UGbfe0VTepUgssw02WHEb8zZ3rOvDpCBFdX -YUvwbw1lkUyvlrc3hBGsOrWqIqlRO8TR2tgZakThkfgVIZi+ZfZKfmSgHzjnb/xM -XF7hT/qdCkcSklxSGUTP434nxwVhhr1dEQYP+soaMliusuBO05wJoxQvtav9FGNd -tteAi24RT+aT9JYQ2UtBXxMYiQE9BBMBCgAnAhsDBQsJCAcDBRUKCQgLBRYCAwEA -Ah4BAheABQJUfftaBQkB47d9AAoJEFAjKZHxDf/QLzAH/1r5JGeD7jf5+vMKNyLj -DXcnbALFe1XyD2tXNQSsj2SDKL3FQmzpFuL5O2XXk6xbCGja2daaDyWvo/FMYg9t -a1DEmPxeWhiFjb1faxya5OA7Be+wqEf7184AK0wO2iTS8ZydOYiibaPBkIC7LPSK -TPFOHuB0OMKBfAyhRe0z404yxX9DoArU6MsBdxndLdgG0Z5s8EzBme+TsV5Y/cNt -+zx0a/+N3CdFZw5eyNM+bzsO/OiSxma9k4rSqMSm/whuiGydRwefufXwJZPITfPB -o0itsZ+r7HBiBY6QR+qqiRjwWGqA6DPuOSRwdObM7XNMc2kvRg4P5w+UPH+y6VPe -C9yJAhwEEgECAAYFAlOZ5aYACgkQGiveqmj9s0z0Fg//cnnBLqytM02vmj7ltvJe -EjdOjwooa8TXGLnkjWqdRtzPCPsCeUWuIJyvsoJDxv5eGkI3MRD5b+2JxE2C+iU6 -NKWE1tbaPnvVn61RgLvi2mDo2j5nHa/AfrLubONWFydwZTc5tsNFvURr7zGWIoac -G01YApHu0JpmUkrZA2nnW/lpPo/1cHVFqvWge5jnJ/4ZBpEhnFedfRe9DYnpKQvs -r/EzZtkCklrL3LjnrrdSg2id29VBWWyG6/SvEl2l53c2Cejo2DNrWBhr1PLslHhr -l2g19xqlf5h+jeqqeLXSzEbEaAJWhH+uk8xHGfrEQ68jWnS1Dd+aSq/6A/MCIV85 -8b/NamZ+RX6qwGs21f9WXZHEhGCcSiQFHr7vK5YjzpirTt1giZFmQ30duPNB3SsQ -6MwNWFz4cXtOiSSUE0bJyjNoNDMOh7jPsnbJEfNM5eKzUPRZvk6fMqsCIvPc5JUt -JOvhSPdrvK7SREDgze79u51sf2sZ79yZ9ryNrCHsnu2heQxnC5PgTTXXULg93I+a -AHPIgVOk4SG+/bpluOpou0M+teAqvUHtaKVv6+EIebkAhgVpH50EvxMgI2N9ivU7 -SW6hAz1FbPOEZAd2uJhs95AbkUxJPG5ETEAy5JOBdmX2BlJ91PVDt+jF7QB/NH57 -y7Or49b0dietE1YsqvyH8fOJARwEEAECAAYFAlTMdN4ACgkQYK8DaOd3WKjK7Qf9 -EXsoNPndlKjUkzxRe3zFZ+rQmqjI9mz9VQrsoFsYctDvCIel//ScsG3pQT+9Jmp2 -j7a/HhrxDwTdOdWR2za7DdfIM4XtaiVFwboltFx9l9a1X5u+1xUgv7xi9+GHIHxf -T5FOI/Bquamu6S87o/kYXq6d7ek1nfrsveEfzpCzI9jpiovy1KgupGR1w7dKIOvA -aqWDcwRM//zvuZudeXziGjGcrGoNL/FQbtVP8haC6ESVugEZcuppV90AbJ9i/syb -mNx5O0/7FDuLAYtEUbzeMmZhe7OA4FjwlowXi+mYYy+76jbIGq0maaU5h9vIS1g4 -6Tl1lrIsDubHwe/5LGtsTbQtT3dlbiBKYWNvYnNvbiA8b3dlbi5qYWNvYnNvbkB1 -bnJlYXNvbmVudC5jb20+iQEcBBMBCgAGBQJT8kuKAAoJENKxmZ8cUdIjD8gH/iGs -DAt4tyVOm6zVVyHlo0nggFJTC9dJsaJH+P8K9OIrWlRE461bXHGmiL13KjNaSPyo -+XFz8rq5aK/rEWwHnZWX6PnyLtCaoTbKdB7LvEOhZpacDGrY7fKBdekwzszVzqCL -s8cBwYRPrUnD0OYPt72qGCMtLaZ3w1Q4dZS8rv5i9LxszUmRwZ407P6r8B5uE5Vm -mZkJf3Fdme+th4hxG1jsqh9rXBLIlGZnhIXC0Llovgj6bLsMvtpKlC6qHj07+7rH -GWnz75xvJ6PnKnhxLgJoEzrn0WMaXCyYADTLiLgJr/X+cFkF1/Al6Yx9VbwIWgA1 -uXFRAZTlCRa1Avja1xuJAT0EEwEKACcCGwMFCwkIBwMFFQoJCAsFFgIDAQACHgEC -F4AFAlR9+1oFCQHjt30ACgkQUCMpkfEN/9AvfwgAhIKjmchMT5JqBdW9k2LyiOTA -Iipw5C6UbiAOSWJ+QXzXEwizQIY+0W9xJeID4UCrainfcfS7C07sfL24sx2bDxfE -di1J2gqu4imtVT8nclXGUancYa7RaWAaqefAKpFUASct2njcIPLCN3HQN09BNVml -iZ5cbHRSKKc3Eg+yIlIcHRczV5tJnpxzTN0swkHCBNYqWmIq0DTZlg24m7eijYpO -Sfru304lDbr6psgvPdjr42uBZcTrwqJfXQdw71/JPRbjPVexJfCahFfISZgCaWIK -thD1bxKRnHs3xLjwUUDl0156mLeGw6ZvGVssRhkWexyONytWAahXWtHzgFByGYkC -HAQSAQIABgUCU5nlpgAKCRAaK96qaP2zTJHXEAChvXef4fRUUIRAZi/pJaX5yexb -IgVfGB9+EBbKwJc/Bj58BUXANdIAIUer85gTkqtxjWGbIuUnABgRcHT6x8BgY3Dk -yAbZZ57r9CxXEnAmzUZFFrSzdIK3yDQbON+Z0zfvozME4OiOP+B8s5uU3jGhzkXZ -32IBCctfGGgqOfdz58HU/DuDBBOI9z5QRZfgn53xzJXJIIOvuGZMFUr/NqvtUqUq -EWJWb0rzvbtTzgYS4hv9vtpMj89UWSf5t+0Rikgo9tTgQoIr1y7jLn1B3JQNzJG3 -ngFNUKuBaR6U683MlR2IXsdv3ysUhkPZj+7+Z5ibTzx6V9DnYaKJ9ZkjqVR4Jmdo -025CDoKuXaCWU5tsAhUxLTi+aGfvgt6cZ1+yy3ICvGbs51cQaaoYnRd4fQtMjWDp -Rm0Cctr1ShVJb/8XlsbLMnkeOSuIlofQfcIbbktl33fMe3tc+dzGTG26YM9Oss9X -dB0oew8MLglpz8o28fBEVCkKolW1aKRftUpGiv/qjH8+URdo3XIxnKuzDxTRI63n -SXPvs9jgPPKnx/Pgbiw2hsEtTQDbvOPRU+32XEnIb557I7nwcMmKCrw0K1AgICz4 -6lGAj/O/IQr7dfS02pmpEItcEwXRr91UzHf3k/kHG46rQX2DF4koXodgy+rDKtDg -oCRrhh7P8Az0DOMph4kBHAQQAQIABgUCVMx03gAKCRBgrwNo53dYqJspB/9z9dG4 -xsHJ0VtaJwqR15fWvhLHnQHuMXlmS340/czebCuJDXwVuhUMRVURBgbTvIieAWhg -dO/xyUeRsbAaMQL38wKM5le1NmY1M9QiryVaJaz23oPQlb1WE8NdIOX28Oz8Iug0 -WjaU1H/ZPTbGO7traUyXfpd/Opha3DGnxzap9mnZMLVMTT97Kj+wbRrDwfHw3sg8 -9VlqKkaQJ0sAhGxAzkyBKf+8V63pE3i8ZHTfG36ot5ssUIX+pKeA1ROhmNeHQ9et -rgBvTSsdXzF5WgegkvgFwjeJ3/d9HFWCZMg/8lJvcLE9GvvAKWh55Vs+6dAXBZo4 -bqTkxeEOd5Bu1asYtCtPd2VuIEphY29ic29uIDxodHRwOi8vdHdpdHRlci5jb20v -ZGVyc3Bpbnk+iQE9BBMBCgAnBQJUv/G4AhsDBQkB47d9BQsJCAcDBRUKCQgLBRYC -AwEAAh4BAheAAAoJEFAjKZHxDf/QytgH/i4C6rgXMr1xR+3PPqO/ruWukA+rs9LP -Kfh/M2fcvPnDFcyDmpP2okL0En0c3HrPMx4983EtMK+10eTxf2nwZfiyId+ze5K2 -lzZmIBEjDfrUon3ls7E3MuRXoqVKhnhywalLynqzE0atFcA9wW6TR0yd/7Q/FWHt -4r2vNsP7BURUh2BSJ5FZuEK2iJojHIz+dyZURPUE8U9wAFAB0ddwOgcSM85SCNIP -UNnGU39VVWWrYf1xMDgzYrfX9mlw/6EES1qL7JU/SDlUX584NJuJ5aHZv2r1bglW -4o9oW7xORb4ABfel4ATuk6MsbJVf1p3EsLlJ87KW3+KEynQN/Ku8MLuJAhwEEgEC -AAYFAlTGi1AACgkQGiveqmj9s0xeEg/+N8kWlLNd7LxWR5WQF3MQl1QdJm2Z/pox -xCIQIyqKoeOHfS+NkyFK0E0MKtXR9PHNARxgr2eCFtDV55bjPgQMJTGO1aLOmoDj -/cXIWiMV52d1Ijw07fZtFGBa/+FsySxzyEe1h8ika/lsfnw0m42UP7IgXezhaZQV -TwFXfglbjc98XYswIwtprtj+AuZKIR6ig7XveF17bjJkXmOiaYSBDPHxVN2vUaQS -aLJlaFOtUNn+NioN6HWNUSzuDPVWy9ck3qMj6CgyrGdlGGdqoQHxNN7RLxCywnHP -KfzWwdX+7asO5dMcMwnHxUHJ+3pVm0myr56Lveica3VAg70N8u99xXCV3Vdx2htu -0gtz2GlfJQeKuSEGPU+gdK86XFNGV8JM/y0OR4GrTnApsmX/FGgcQZynbBJ2/8UH -6WA29Lffp+/pz0jilj3hwSsK6wwPN49/m9qszoOPyT8WJhDt0Vj6YA64N8NOzKLq -XZa4MwnaCZiChjjCPrmElQPcR4RQZwAhm0t+8uw1/6hyZkjHJ5uO/7LsEgxwYCU/ -idqTSf3DQMcvk4MEaWuDwRZ3Nm6tj+F2oaqkqT1LcyB4OYa2PKpgxvLDwSNFmG75 -d7uXJHbAlg6t9ysmWkxah7/L8eNsmU32eXFuNP6detR7zCOLYARaTLe2CWOF0OI/ -8nSng+hSUf+JARwEEAECAAYFAlTMdN4ACgkQYK8DaOd3WKg2BAf/Qn0BNlGfhL/f -YcTYWgTRkehVBXRaQ/hSjrdcyfMc4IXPeSXrZ8WZUi4QHLauFx1XtKTzVPWx8ggU -reZPo50wwev1N/iOPvQhh8Q+Y0SNHY1S824AHDjDnLp7+XuBX/oYArtxorUufdxA -G6jtkSabUm1ucGGs6ccF+UXs4E/NMiVkXfP1GCCm+Upgwhunk/9Mr6BaSJKZLYK3 -3NdwmiNlMLSnVxXBaZHzs/dLdqRKZF11fkRfBWpBaIUjOMEwjuHakoUmDONeDmv7 -+DlK46V2jIL2r6f+39XeAsnxvCF5mNJGPGnMMtaEuCqMcDbdQMnZdRE3rqLGQE43 -BPvwCDXvArQjT3dlbiBKYWNvYnNvbiA8aHR0cDovL2dyaW1vaXJlLmNhLz6JAT0E -EwEKACcFAlS/8c8CGwMFCQHjt30FCwkIBwMFFQoJCAsFFgIDAQACHgECF4AACgkQ -UCMpkfEN/9AG0wf+O39YDA32Qrx9VqpKeJhx/m/s6kaux7cDPZmehMQOCts5UAZi -oXZyDYUWcpHSZJEcmzUnKYO/8xAJSLUQvmVvcEUg2mQ72Xs4OsFta2DMw3tue3OY -ZZZfhUqkG/zoUGAVYZz3hhTbvTaUMbnVrm1GiRhdAFVrnzSh/AxMV+krB1c0O8h+ -ses2Yk4L1edBVxMqqwzjGBupI/q1NXTnkwXZ7+gBG8XlapuQ309Sa+ufk8W/bo4T -Q92ZOQReM1b4IdwCX4IwPinT0KAQ0eqVRNCsFYy7KuvkxUoqhHWFXia9QSeuY8E7 -1m59xt4rIiUcEn2i+CWYpydPy6zLTBtqCYY1ookCHAQSAQIABgUCVMaLRgAKCRAa -K96qaP2zTBqkD/9VkcEyaeYkYrU34oaeWfOR93MZS4DEBIsKjUD0QVTvVb0CLXRU -+92POUCSQlqhv9nF4emrLCjDQTXgW/TmM6gl9UTDGsWMpmfIuTlJcQHGkqhXKN/i -Egb0Xkutt+q6tnvpgX1lWOBGO6upmVqnQYRcKVdfkArmD3tGoaIZsb/vWOgp4OGY -DvGYpuaasdkLaBFGPGYEuyofkgrU8ssO4xq9SdGUOhgAkFrl78iTXIpe5VTOy3Lo -VwWSUv10JKK3Yz+LxlYDUTiXKFm/mkvV6NhZMDMsCyXPJcsGZlpP7fT2JrJJ5Akf -PMw+6FXTuY54hBtZEze+ukrnhXd8QV7e149UYpMT+9OHYysLRmQ7//2HUsPGwlvQ -zVTzee2D/LTtFUiwt2b6aU/7yvJRTraqCaZlotOuPM5ZlimbPUTsqahP46Y7NNx/ -oE/vcEAJu+C2r48gcLmf6g9IK5WUEsX8ZcSY/UhTECsMOqQUqmuNRRaqvujLV22V -5oMKHDb8fzG0Cbgm/qP5o5RpAgCG7iL/xeKfi7XZJ582wpIoV4JJrGjVrzgK0Ljf -/xntdCL/2hUbxM93+djJFWIaqerAkbzEYznt+N/ZCqSApiDwedukyiJkCPm0Zz1D -owd29g3SJsUDzroaSAEMRYkMH8EdFeOJFcmrMjQhQJIEypdZ5Ll3JK1v0YkBHAQQ -AQIABgUCVMx03gAKCRBgrwNo53dYqJfTB/wPZvD8enoGEU4ZeXTXYQ53wYqYF13F -JNikrmj8Ze+IsYuZprXJKzLRkL2DnbdNW91BudibPJo0DeLiyXGA8pw2IGCllfkp -a6ZtxalPJWJLAbiOmXzui/HJ2Md1tnSDGfKCZ6MiaQQ0ceKoqOhPP7d3Vtcc5uQk -zSYQu6SqKmCrjicnu+hWKAT9Iy21wvBCLJkYMit/Bzue7NRV+PwYLdD24ZXwKfny -P9I33gcxEMIeG6L042NVUY1vsySYrcXRsXyIvYvd2CH1FqQY1GPTcUEQbQH21v5z -/PtgYv/UCckRJvEJUDE8DCF168FnflVB1ZHLmFNCrcLlrSKwydmuzNIUtCJPd2Vu -IEphY29ic29uIDxkZXJzcGlueUBnbWFpbC5jb20+iQE9BBMBCgAnBQJUyqInAhsD -BQkB47d9BQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEFAjKZHxDf/Q5+8H/2kX -yOTkDbO2Ik6oH149341k8GiLPiMMSj0WS8OBquBc3Hi+Upr2jOvl5KljkPU3qshb -O2ry6yLWFC38C3PjIRdBYpUfoUVKAoVRaTUMuO7RGgZuMzQFajMM+dcDZxRsfFoW -aInjFDxlwqFwF+AAvT9rsK/3t/MF9WdM6B+XhEsApY0zu6xdT8eXM08y3iVoYHbD -hVs1/czc3qBhG3IJGI1N7dU+fHDpdQSYf8zCifgLGridPQDkqAeLQE6QtoIw/r+I -NeYuCnl+zrGdlF7yyWlQUGulGUF4XRDt50WIIzAhtrCeVwdV5/EkGmXyA17KU3EP -KrBWUu00itxZyKljSIqJARwEEAECAAYFAlTMdN4ACgkQYK8DaOd3WKhmNggAlyWL -vhQdffZpuhL0Wd7Kyz8hB0WxXABQr03WCwtzCY5d+SwvjpI7RvHVRxOLcz6CISXT -DTVVQXzcYXyENSQSxqiRUEaOl4dlnGXQx/h6KVQ4akBu/hLo/nz5vfiN0YPqa98G -tT2J1SL0wRX6w6KtMqONmThKoiVYpbl39vjf4PvGzmptUvMSFlq7xHUQ0KGyfya9 -ZdLOZwqmhonwIdL8MIXAZqFpIXaP9az8IX9ecr9Kq02U7P9hNlrM9G8QiSdCEfss -JS3YPQRso0NjEFdKIyTKwl+hWYyvMJqtRyM6XIi8gbUSIu5GvqZqMkRN8beiRcfg -2glvXeccQtoLeK7NF7kBDQRTlhJYAQgA16Y1Y1+c7RmV5cpPRr8kn7kp8ecsow6Y -5A2IFN6kx+cNrkzH0TbEswLTwUQEmYEJfNmBwEy3LJER4IV5MRMZmEwdbwAu/2k7 -DolcNvfeIhbQtWtNq9EuI5meEeQTFf5Lpo4OqcCyPtMy7jE+1bs0f415SMuRZgWE -btecQNst8BNSV73CGNtatIa535hN2RN4IjiujOs5iDR7U2KNeEe0xfBxOG3JKqJD -Q9JAKWGE9qY4ZiGQjX9YC/4QOwT+jZQZJHZgL86Sdq07x/d9QA2r6ZGK4kpu1zEf -ABO+oMUSG+7M5Rqdgf5QOlNEbRT/PocAH4NIbg5JW+VNqgd9n8E+/QARAQABiQEf -BBgBCgAJAhsMBQJUq17dAAoJEFAjKZHxDf/Q7CIH/2WmlrHQKycRSoLTjav6PXWq -7Zt2XyvVa+TbgXy/xtvUYhRJLlVSNM8Fux6xnW5ndwwoV41yYKLTdTOkZD3GF8GB -k01xwThp5T+Xex9jzo97UdMnIrBc8uQSM3LUdH/aivQLQW2cElTQ1EiGA+ytMpHG -kCbMHm0ZL0ATSuYEJB8ngTl3a3nCUXNH3eDAYaSwCAxtR/97E/VbT8VRdIIuwj74 -+8mQwbK0xMJwk3rX3DU5KA7KeRXxrV/pvrrMJpVEVzviHYCdRpna2OEFx7fGTSEv -5TR10QF6ZmN/hqnihFFDzFM9lOhaAfB1/u7WgYK+KzCTQETvdxYIccjQvryc4E4= -=EdOy ------END PGP PUBLIC KEY BLOCK----- -</code></pre> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/gpg/keys.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/gpg/keys.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/gpg/terrible.html b/.html/gpg/terrible.html deleted file mode 100644 index 59f4afb..0000000 --- a/.html/gpg/terrible.html +++ /dev/null @@ -1,198 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - GPG Is Terrible - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">gpg</a> - - </li> - - <li class="crumb-2 last"> - - terrible - - </li> - - </ol> - - - - <div id="article"> - <h1 id="gpg-is-terrible">GPG Is Terrible</h1> -<p>A discussion at work reminded me that I hadn't looked at the state of the art -for email and communications security in a while. Turns out the options -haven't changed much: S/MIME, which relies on x.509 PKI and is therefore -unusable unless you want to pay for a certificate from someone with lots of -incentives to screw you, or GPG.</p> -<p>S/MIME in the wild is a total non-starter. GPG, on the other hand, is merely -really, <em>really</em> bad.</p> -<p>(You may want to take this with a side of <a href="cool">the other perspective</a>.)</p> -<h2 id="body-security-and-nothing-else">Body Security And Nothing Else</h2> -<p>GPG encrypts and signs email message bodies. That's it, that's all it does -when integrated with email. Email messages contain lots of other useful, -potentially sensitive data: the subject line, for example. GPG still exposes -all of the headers for the world to see, and conversely does nothing to -detect or prevent header tampering by idiot mailers.</p> -<p>(Yes. Signed headers <em>would</em> mean that mailing lists can no longer inject -<code>[listname]</code> crud into your messages. Feature, not bug; we should be, and in -many cases already are, storing that in a header of its own, not littering -the subject line. We also need to keep improving mail tooling, to better -handle those headers.)</p> -<p>In return for doing about half of its One Job, GPG demands a <em>lot</em> from its -users.</p> -<h2 id="the-real-name-policy">The Real Name Policy</h2> -<p>The GPG community has a massive “legal names” fixation. <a href="http://cryptnet.net/fdp/crypto/keysigning_party/en/extra/signing_policy.html">Widespread GPG -documentation</a>, -and years of community inertia, stand behind expecting people to put their -legal name in their GPG key, and conversely expecting people to verify the -identity in a GPG key (generally by checking government ID) before signing it.</p> -<p>As the <a href="http://www.jwz.org/blog/2011/08/nym-wars/">#nymwars</a> folks can tell -you, this policy is harmful and limiting. There are good theoretical reasons -to validate <em>an</em> identity before using its keys to secure messages, but legal -identities can be anywhere from awkward to dangerous to use.</p> -<p>GPG does not <em>technically</em> restrict users from creating autonymous keys, but -the community at large discourages their use unless they can be traced back -to some legal identity. Autonyms keys tend to go unsigned by any other key, -cutting them off from the GPG trust network's validation effect.</p> -<p>As <a href="https://twitter.com/wlonk/">@wlonk</a> put it:</p> -<blockquote> -<p>I care about communicating with the coherent theory of mind behind @so-and-so.</p> -</blockquote> -<h2 id="issuing-identities">Issuing Identities</h2> -<p>GPG makes issuing new identities simultaneously too easy and too hard for users. -It's hard, because the <em>only</em> way to issue a new identity on an existing key -(and thus associated with and able to share correspondence with an existing -identity) requires that the user have access to their personal root key. There's -no way to create ad-hoc identities and bind them after the fact, making it hard -to implement opportunistic tools. (OTR's on-demand key generation fails to the -opposite extreme.) It's easy, because there's no mechanism beyond the web of -trust itself to vet newly-created keys or identities; the GPG community -compounds this by demanding that everyone carefully vet legal identities, making -it <em>very</em> time-consuming to deploy a new name.</p> -<h2 id="finding-paul-revere">Finding Paul Revere</h2> -<p>It turns out autonymity in GPG would be pretty fragile even if GPG's user -community <em>didn't</em> insist on puncturing it at every opportunity, since GPG -irrevocably publishes the social graph of its users to every keyserver they -use. You don't even have to publish it yourself; anyone who has a copy of -your public key can upload a copy for you, revealing to the world the -identities of everyone who knows you well enough to sign your key, and when -they signed it.</p> -<p>A lot of people can be meaningfully identified by that information alone, -even without publishing their personal identity.</p> -<h2 id="the-web-of-vulnerable-cas">The Web Of Vulnerable CAs</h2> -<p>Each GPG user is also a unilateral signing authority. GPG's trust model means -that a compromised key can be used to confer validity onto <em>any</em> other key, -compromising potentially many other users by causing them to trust -illegitimate keys. GPG assumes everyone will be constantly on watch for -unusual signing activity, and perfectly aware of the safety of their own keys -at all times.</p> -<p>Given that the GPG signature graph is largely public, it should be possible to -moderate signatures using clique analysis, limiting the impact of a trusted -party who signs inauthentic identities. Unfortunately, GPG makes it challenging -to implement this by providing almost no support for iteratively deepening the -local keyring by downloading signers' keys as needed.</p> -<h2 id="interoperability">Interoperability</h2> -<p>Sending a GPG-signed message to a non-GPG-using normal human being is a great -way to confuse the hell out of them. You have two options:</p> -<ul> -<li>In-band “cleartext” signing, which litters the email body with technical - noise, or</li> -<li>PGP/MIME, which delivers a meaningless-looking “signature.asc” attachment.</li> -</ul> -<p>In both cases, the recipient is left with a bunch of information they (a) -can't use and (b) can't hide or remove. It might as well say “virus.dat” for -all the meaning it conveys.</p> -<p>Some of this is not GPG's fault, exactly, but after over a decade, surely -either advocacy or compromise with major mail vendors should have been -possible.</p> -<p>(Accidentally sending an <em>encrypted</em> email to a non-GPG-using recipient is, -thankfully, hard enough to be irrelevant unless someone is actively spoofing -their identity.)</p> -<h2 id="webmail-need-not-apply">Webmail Need Not Apply</h2> -<p>Well, unless you want to write the message text in an editor, copy and paste -it into GPG, and copy and paste the encrypted blob back out into your -message. (Hope your webmail's online editor doesn't mangle dashes or quotes -for you!)</p> -<p>Apparently Google's <a href="https://code.google.com/p/end-to-end/">finally fixing that for Chrome -users</a>, so that's something.</p> -<h2 id="mobile-need-not-apply">Mobile Need Not Apply</h2> -<p><del>Safely distributing GPG keys to mobile applications is more or less -impossible, and integration with mobile mail applications is nonexistant. -Hope you only ever read your mail from a Real Computer!</del></p> -<p>vollkorn points out that the above is inaccurate. He posted a couple of -options for GPG on Android, and the state of the art for iOS GPG apps is -apparently better than I was able to find. See <a href="#comment-1422227740">his -comment</a> for details.</p> -<h2 id="further-reading">Further Reading</h2> -<ul> -<li><a href="http://secushare.org/PGP">Secushare.org's “15 reasons not to start using PGP”</a></li> -<li><a href="https://lists.torproject.org/pipermail/tor-talk/2013-September/030235.html">Mike Perry's “Why the Web of Trust Sucks”</a></li> -</ul> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/gpg/terrible.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/gpg/terrible.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/hire-me.html b/.html/hire-me.html deleted file mode 100644 index fc3e45d..0000000 --- a/.html/hire-me.html +++ /dev/null @@ -1,187 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Hire Me - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="./">index</a> - - </li> - - <li class="crumb-1 last"> - - hire-me - - </li> - - </ol> - - - - <div id="article"> - <h1 id="hire-me">Hire Me</h1> -<p>I'm always interested in hearing from people and organizations that I can help, -whether that means coming in for a few days to talk about end-to-end testing or -joining your organization full-time to help turn an idea into reality.</p> -<p>I live in and around Toronto, ON. I am more than happy to work remotely, and I -can probably help your organization learn to integrate remote work if it doesn't -already know how.</p> -<p>You can see more about me as a person on -<a href="https://hiremyfriend.io/profiles/90b8caa5">HireMyFriend</a> or -<a href="https://ca.linkedin.com/in/ojacobson/">LinkedIn</a>. You can also get a sense of -the code I write by looking at this blog, as well as my -<a href="https://bitbucket.org/ojacobson">Bitbucket</a> or -<a href="https://github.com/ojacobson/">Github</a> sites: I recommend starting with -<a href="https://github.com/ojacobson/refreshbooks">Refreshbooks</a> or -<a href="https://github.com/ojacobson/sparkplug">Sparkplug</a>.</p> -<h2 id="for-fun">For Fun</h2> -<p>I regularly revisit problems from old jobs, interesting ideas from the internet, -and whatever else catches my fancy as a way to build up skills with specific -technologies. Right now, I'm tinkering with <a href="http://angularjs.org">AngularJS</a> -and <a href="https://jersey.java.net">Jersey 2</a> as a way of building lightweight, -highly-responsive web front ends. Ask me about it and I'll be more than happy to -talk your ear off. I've also run similar projects to explore Node, Django, -Flask, Rails, and other platforms for web development, as well as numerous tools -and frameworks for other platforms.</p> -<p>I also mentor people new to programming, teaching them how to craft working -systems. This is less about teaching people to write code and more about -teaching them why we care about source control, how to think about -configuration, how to and why to automate testing, and how to think about -software systems and data flow at a higher level. I strongly believe that -software development needs a formal apprenticeship program, and mentoring has -done a lot to validate that belief.</p> -<h2 id="freshbooks-2009-2014">FreshBooks (2009-2014)</h2> -<p>During the five years I was with the company, it grew from a 20-person one-room -organization to a healthy, growing two-hundred-person technology company. As an -early employee, I had my hand in many, many projects and helped the development -team absorb the massive cultural changes that come with growth, while also -building a SaaS product that let others realize their dreams. Some highlights:</p> -<ul> -<li> -<p>As the lead <a href="http://grimoire.ca/mysql/choose-something-else">MySQL</a> database - administrator-slash-developer, I worked with the entire development team to - balance concerns about reliability and availability with ensuring new ideas - and incremental improvements could be executed without massive bureaucracy - and at low risk. This extended into diverse parts of the company: alongside - the operations team, I handled capacity planning, reliability, outage - planning, and performance monitoring, while with the development team, I - was responsible for designing processes and deploying tools to ease testing - of database changes and ensuring smooth, predictable, and <em>low-effort</em> - deployment to production and for training developers to make the best use of - MySQL for their projects.</p> -</li> -<li> -<p>As a tools developer, I built the <a href="https://pypi.python.org/pypi/sparkplug">Sparkplug</a> - framework to standardize the tools and processes for building message-driven - applications, allowing the team to move away from monolithic web applications - towards a more event-driven suite of interal systems. Providing a standard - framework paid off well; building and deploying completely novel event - handlers for FreshBooks’ core systems could be completed in as little as a - week, including testing and production provisioning.</p> -</li> -<li> -<p>As an ops-ish toolsmith, I worked extensively on configuration management - for both applications and the underlying servers. I lead a number of - projects to reduce the risk around deployments: creating a standard - development VM to ensure developers had an environment consistent with - reality, automating packaging and rollout to testing servers, automating the - <em>creation</em> of testing servers, and more. As part of this work, I built - training materials and ran sessions to teach other developers how to think - like a sysadmin, covering Linux, Puppet, virtualization, and other topics.</p> -</li> -</ul> -<h2 id="riptown-media-2006-2009">Riptown Media (2006-2009)</h2> -<p>Riptown Media was an software development company tasked with building and -maintaining a suite of gambling systems for a single client. I was brought on -board as a Java developer, and rapidly expanded my role to encompass other -fields.</p> -<ul> -<li> -<p>As the primary developer for poker-room back office and anti-fraud tools, I - worked with the customer support and business intelligence teams to better - understand their daily needs and frustrations, so that I could turn those - into meaningful improvements to their tools and processes. These - improvements, in turn, lead to measurable changes in the frequency and - length of customer support calls, in fraud rates, and in the percieved value - of internal customer intelligence.</p> -</li> -<li> -<p>As a lead developer, my team put together the server half of an in-house - casino gaming platform. We worked in tight collaboration with the client - team, in-house and third-party testers, and interaction designers, and - delivered our first game in under six months. Our platform was meant to - reduce our reliance on third-party “white label” games vendors; internally, - it was a success. Our game received zero customer-reported defects during - its initial run.</p> -</li> -</ul> -<h2 id="osi-geospatial-2004-2006">OSI Geospatial (2004-2006)</h2> -<p>At OSI Geospatial, I lead the development of a target-tracking and battlespace -awareness overlay as part of a suite of operational theatre tools. In 2004, the -state of the art for web-based geomatics software was not up to the task; this -ended up being a custom server written in C++ and making heavy use of PostgreSQL -and PostGIS for its inner workings.</p> -<h2 id="contact-me">Contact Me</h2> -<p>Sound good? Curious? Want to discuss any of this some more? You can get ahold of -me at owen.jacobson@grimoire.ca or on <a href="https://twitter.com/derspiny">Twitter</a>.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/hire-me.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/hire-me.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/index.html b/.html/index.html deleted file mode 100644 index 503621a..0000000 --- a/.html/index.html +++ /dev/null @@ -1,130 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls / - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="./">index</a> - - </li> - - <li class="crumb-1 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /</code></h1> - - - <div id="directories"> - <h2>Directories</h2> - <ul> - - <li><a href="12factor/">12factor/</a></li> - - <li><a href="authnz/">authnz/</a></li> - - <li><a href="dev/">dev/</a></li> - - <li><a href="devops/">devops/</a></li> - - <li><a href="ethics/">ethics/</a></li> - - <li><a href="git/">git/</a></li> - - <li><a href="gossamer/">gossamer/</a></li> - - <li><a href="gpg/">gpg/</a></li> - - <li><a href="java/">java/</a></li> - - <li><a href="media/">media/</a></li> - - <li><a href="muds/">muds/</a></li> - - <li><a href="mysql/">mysql/</a></li> - - <li><a href="people/">people/</a></li> - - <li><a href="toronto/">toronto/</a></li> - - </ul> - </div> - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="cool-urls-can-change">Cool URLs Do Change (Sometimes)</a></li> - - <li><a href="hire-me">Hire Me</a></li> - - <li><a href="email">Why I Didn't Answer Your Email</a></li> - - <li><a href="packaging-ideas">Why “Web 2.0” Matters</a></li> - - </ul> - </div> - - - - <div id="files"> - <h2>Files</h2> - - <li><a href="keybase.txt">keybase.txt</a></li> - - </div> - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/java/_list.html b/.html/java/_list.html deleted file mode 100644 index 4b6c78f..0000000 --- a/.html/java/_list.html +++ /dev/null @@ -1,101 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /java - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">java</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /java</code></h1> - - - <div id="directories"> - <h2>Directories</h2> - <ul> - - <li><a href="install/">install/</a></li> - - </ul> - </div> - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="a-new-kind-of">A New Kind of Java</a></li> - - <li><a href="kwargs">Keyword Arguments in Java</a></li> - - <li><a href="stop-using-class-dot-forname">Stop Using Class Dot Forname</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/java">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/java/a-new-kind-of.html b/.html/java/a-new-kind-of.html deleted file mode 100644 index 764fb45..0000000 --- a/.html/java/a-new-kind-of.html +++ /dev/null @@ -1,203 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - A New Kind of Java - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">java</a> - - </li> - - <li class="crumb-2 last"> - - a-new-kind-of - - </li> - - </ol> - - - - <div id="article"> - <h1 id="a-new-kind-of-java">A New Kind of Java</h1> -<p>Java 8 is almost here. You can <a href="http://jdk8.java.net/download.html">play with the early access -previews</a> right now, and I think you -should, even if you don't like Java very much. There's so much <em>potential</em> in -there.</p> -<h2 id="the-one-more-thing">The “One More Thing”</h2> -<p>The Java 8 release comes with a slew of notable library improvements: the new -<a href="http://openjdk.java.net/jeps/150"><code>java.time</code></a> package, designed by the folks -behind the extremely capable Joda time library; <a href="http://openjdk.java.net/jeps/118">reflective -access</a> to parameter names; <a href="http://openjdk.java.net/jeps/133">Unicode -6.2</a> support; numerous others. But all of -these things are dwarfed by the “one last thing”:</p> -<p><strong>Lambdas</strong>.</p> -<h2 id="ok-so">Ok, So..?</h2> -<p>Here's the thing: all of the “modern” languages that see regular use - C#, -Python, Ruby, the various Lisps including Clojure, and Javascript - have -language features allowing easy creation and use of one-method values. In -Python, that's any object with a <code>__call__</code> method (including function -objects); in Ruby, it's blocks; in Javascript, it's <code>function() {}</code>s. These -features allow <em>computation itself</em> to be treated as a value and passed -around, which in turn provides a very powerful and succinct mechanism for -composing features.</p> -<p>Java's had the “use” side down for a long time; interfaces like <code>Runnable</code> are -a great example of ways to expose “function-like” or “procedure-like” types to -the language without violating Java's bureaucratic attitude towards types and -objects. However, the syntax for creating these one-method values has always -been so verbose and awkward as to discourage their use. Consider, for example, -a simple “task” for a thread pool:</p> -<pre><code>pool.execute(new Runnable() { - @Override - public void run() { - System.out.println("Hello, world!"); - } -}); -</code></pre> -<p>(Sure, it's a dumb example.)</p> -<p>Even leaving out the optional-but-recommended <code>@Override</code> annotation, that's -still five lines of code that only exist to describe to the compiler how to -package up a block as an object. Yuck. For more sophisticated tasks, this sort -of verbosity has lead to multi-role “event handler” interfaces, to amortize -the syntactic cost across more blocks of code.</p> -<p>With Java 8's lambda support, the same (dumb) example collapses to</p> -<pre><code>pool.execute(() -> System.out.println("Hello, world")); -</code></pre> -<p>It's the same structure and is implemented very similarly by the compiler. -However, it's got much greater informational density for programmers reading -the code, and it's much more pleasant to write.</p> -<p>If there's any justice, this will completely change how people design Java -software.</p> -<h2 id="event-driven-systems">Event-Driven Systems</h2> -<p>As an example, I knocked together a simple “event driven IO” system in an -evening, loosely inspired by node.js. Here's the echo server I wrote as an -example application, in its entirety:</p> -<pre><code>package com.example.onepointeight; - -import java.io.IOException; - -public class Echo { - public static void main(String[] args) throws IOException { - Reactor.run(reactor -> - reactor.listen(3000, client -> - reactor.read(client, data -> { - data.flip(); - reactor.write(client, data); - }) - ) - ); - } -} -</code></pre> -<p>It's got a bad case of Javascript “arrow” disease, but it demonstrates the -expressive power of lambdas for callbacks. This is built on NIO, and runs in a -single thread; as with any decent multiplexed-IO application, it starts to -have capacity problems due to memory exhaustion well before it starts to -struggle with the number of clients. Unlike Java 7 and earlier, though, the -whole program is short enough to keep in your head without worrying about the -details of how each callback is converted into an object and without having to -define three or four extra one-method classes.</p> -<h2 id="contextual-operations">Contextual operations</h2> -<p>Sure, we all know you use <code>try/finally</code> (or, if you're up on your Java 7, -<code>try()</code>) to clean things up. However, context isn't always as tidy as that: -sometimes things need to happen while it's set up, and un-happen when it's -being torn down. The folks behind JdbcTemplate already understood that, so you -can already write SQL operations using a syntax similar to</p> -<pre><code>User user = connection.query( - "SELECT login, group FROM users WHERE username = ?", - username, - rows -> rows.one(User::fromRow) -); -</code></pre> -<p>Terser <strong>and</strong> clearer than the corresponding try-with-resources version:</p> -<pre><code>try (PreparedStatement ps = connection.prepare("SELECT login, group FROM users WHERE username = ?")) { - ps.setString(1, username); - try (ResultSet rows = rs.execute()) { - if (!rows.next()) - throw new NoResultFoundException(); - return User.fromRow(rows); - } -} -</code></pre> -<h2 id="domain-specific-languages">Domain-Specific Languages</h2> -<p>I haven't worked this one out, yet, but I think it's possible to use lambdas -to implement conversational interfaces, similar in structure to “fluent” -interfaces like -<a href="http://docs.oracle.com/javaee/6/api/javax/ws/rs/core/UriBuilder.html">UriBuilder</a>. -If I can work out the mechanics, I'll put together an example for this, but -I'm half convinced something like</p> -<pre><code>URI googleIt = Uris.create(() -> { - scheme("http"); - host("google.com"); - path("/"); - queryParam("q", "hello world"); -}); -</code></pre> -<p>is possible.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/java/a-new-kind-of.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/java/a-new-kind-of.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/java/index.html b/.html/java/index.html deleted file mode 100644 index 4b6c78f..0000000 --- a/.html/java/index.html +++ /dev/null @@ -1,101 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /java - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">java</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /java</code></h1> - - - <div id="directories"> - <h2>Directories</h2> - <ul> - - <li><a href="install/">install/</a></li> - - </ul> - </div> - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="a-new-kind-of">A New Kind of Java</a></li> - - <li><a href="kwargs">Keyword Arguments in Java</a></li> - - <li><a href="stop-using-class-dot-forname">Stop Using Class Dot Forname</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/java">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/java/install/_list.html b/.html/java/install/_list.html deleted file mode 100644 index 4af64c6..0000000 --- a/.html/java/install/_list.html +++ /dev/null @@ -1,96 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /java/install - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="../">java</a> - - </li> - - <li class="crumb-2 not-last"> - - <a href="./">install</a> - - </li> - - <li class="crumb-3 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /java/install</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="centos">Installing Java on CentOS</a></li> - - <li><a href="ubuntu">Installing Java on Ubuntu</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/java/install">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/java/install/centos.html b/.html/java/install/centos.html deleted file mode 100644 index 9bbf3f4..0000000 --- a/.html/java/install/centos.html +++ /dev/null @@ -1,136 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Installing Java on CentOS - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="../">java</a> - - </li> - - <li class="crumb-2 not-last"> - - <a href="./">install</a> - - </li> - - <li class="crumb-3 last"> - - centos - - </li> - - </ol> - - - - <div id="article"> - <h1 id="installing-java-on-centos">Installing Java on CentOS</h1> -<p>Verified as of CentOS 5.8, Java 6. CentOS 6 users: fucking switch to Debian -already. Is something wrong with you? Do you like being abused by your -vendors?</p> -<h2 id="from-package-management-yum">From Package Management (Yum)</h2> -<p>OpenJDK is available via <a href="http://fedoraproject.org/wiki/EPEL/FAQ">EPEL</a>, from -the Fedora project. Install EPEL before proceeding.</p> -<p>You didn't install EPEL. Go install EPEL. <a href="http://fedoraproject.org/wiki/EPEL/FAQ#Using_EPEL">The directions are in the EPEL -FAQ</a>.</p> -<p>Now install the JDK:</p> -<pre><code>sudo yum install java-1.6.0-openjdk-devel -</code></pre> -<p>Or just the runtime:</p> -<pre><code>sudo yum install java-1.6.0-openjdk -</code></pre> -<p>The RPMs place the appropriate binaries in <code>/usr/bin</code>.</p> -<p>Applications that can't autodetect the JDK may need <code>JAVA_HOME</code> set to -<code>/usr/lib/jvm/java-openjdk</code>.</p> -<h2 id="by-hand">By Hand</h2> -<p>The <a href="http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html">Java SE Development Kit -7</a> -tarballs can be installed by hand. Download the “Linux x64” <code>.tar.gz</code> version, -then unpack it in <code>/opt</code>:</p> -<pre><code>cd /opt -tar xzf ~/jdk-7u45-linux-x64.tar.gz -</code></pre> -<p>This will create a directory named <code>/opt/jdk1.7.0_45</code> (actual version number -may vary) containing a ready-to-use Java dev kit.</p> -<p>You will need to add the JDK's <code>bin</code> directory to <code>PATH</code> if you want commands -like <code>javac</code> and <code>java</code> to work without fully-qualifying the directory:</p> -<pre><code>cat > /etc/profile.d/oracle_jdk <<'ORACLE_JDK' -PATH="${PATH}:/opt/jdk1.7.0_45/bin" -export PATH -ORACLE_JDK -</code></pre> -<p>(This will not affect non-interactive use; setting PATH for non-interactive -programs like build servers is beyond the scope of this document. Learn to use -your OS.)</p> -<p>Installation this way does <em>not</em> interact with the alternatives system (but -you can set that up by hand if you need to).</p> -<p>For tools that cannot autodetect the JDK via <code>PATH</code>, you may need to set -<code>JAVA_HOME</code> to <code>/opt/jdk1.7.0_45</code>.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/java/install/centos.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/java/install/centos.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/java/install/index.html b/.html/java/install/index.html deleted file mode 100644 index d167e58..0000000 --- a/.html/java/install/index.html +++ /dev/null @@ -1,102 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Installing Java … - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="../">java</a> - - </li> - - <li class="crumb-2 last"> - - install - - </li> - - </ol> - - - - <div id="article"> - <h1 id="installing-java">Installing Java …</h1> -<p>This document provided as a community service to -<a href="irc://irc.freenode.org/##java">##java</a>. Provided as-is; pull requests -welcome.</p> -<ol> -<li> -<p><a href="ubuntu">… on Ubuntu</a> (may also be applicable to Debian; needs verification - from a Debian user)</p> -</li> -<li> -<p><a href="centos">… on CentOS</a> (probably also applicable to RHEL; needs verification - from a RHEL user)</p> -</li> -</ol> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/java/install/index.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/java/install/index.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/java/install/ubuntu.html b/.html/java/install/ubuntu.html deleted file mode 100644 index 0d81292..0000000 --- a/.html/java/install/ubuntu.html +++ /dev/null @@ -1,158 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Installing Java on Ubuntu - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="../">java</a> - - </li> - - <li class="crumb-2 not-last"> - - <a href="./">install</a> - - </li> - - <li class="crumb-3 last"> - - ubuntu - - </li> - - </ol> - - - - <div id="article"> - <h1 id="installing-java-on-ubuntu">Installing Java on Ubuntu</h1> -<p>Accurate as of: Java 7, Ubuntu 12.04. The instructions below assume an amd64 -(64-bit) installation. If you're still using a 32-bit OS, work out the -differences yourself.</p> -<h2 id="via-package-management-apt">Via Package Management (Apt)</h2> -<p>OpenJDK 7 is available via apt by default.</p> -<p>To install the JDK:</p> -<pre><code>sudo aptitude update -sudo aptitude install openjdk-7-jdk -</code></pre> -<p>To install the JRE only (without the JDK):</p> -<pre><code>sudo aptitude update -sudo aptitude install openjdk-7-jre -</code></pre> -<p>To install the JRE without GUI support (appropriate for headless servers):</p> -<pre><code>sudo aptitude update -sudo aptitude install openjdk-7-jre-headless -</code></pre> -<p>(You can also use <code>apt-get</code> instead of <code>aptitude</code>.)</p> -<p>These packages interact with <a href="http://manpages.ubuntu.com/manpages/hardy/man8/update-alternatives.8.html">the <code>alternatives</code> -system</a>, -and have <a href="http://manpages.ubuntu.com/manpages/hardy/man8/update-java-alternatives.8.html">a dedicated <code>alternatives</code> manager -script</a>. -The <code>alternatives</code> system affects <code>/usr/bin/java</code>, <code>/usr/bin/javac</code>, and -browser plugins for applets and Java Web Start applications for browsers -installed via package management. It also affects the symlinks under -<code>/etc/alternatives</code> related to Java.</p> -<p>To list Java versions available, with at least one Java version installed via -Apt:</p> -<pre><code>update-java-alternatives --list -</code></pre> -<p>To switch to <code>java-1.7.0-openjdk-amd64</code> for all Java invocations:</p> -<pre><code>update-java-alternatives --set java-1.7.0-openjdk-amd64 -</code></pre> -<p>The value should be taken from the first column of the <code>--list</code> output.</p> -<h3 id="tool-support">Tool support</h3> -<p>Most modern Java tools will pick up the installed JDK via <code>$PATH</code> and do not -need the <code>JAVA_HOME</code> environment variable set explicitly. For applications old -enough not to be able to detect the JDK, you can set <code>JAVA_HOME</code> to -<code>/usr/lib/jvm/java-1.7.0-openjdk-amd64</code>.</p> -<h2 id="by-hand">By Hand</h2> -<p>The <a href="http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html">Java SE Development Kit -7</a> -tarballs can be installed by hand. Download the “Linux x64” <code>.tar.gz</code> version, -then unpack it in <code>/opt</code>:</p> -<pre><code>cd /opt -tar xzf ~/jdk-7u45-linux-x64.tar.gz -</code></pre> -<p>This will create a directory named <code>/opt/jdk1.7.0_45</code> (actual version number -may vary) containing a ready-to-use Java dev kit.</p> -<p>You will need to add the JDK's <code>bin</code> directory to <code>PATH</code> if you want commands -like <code>javac</code> and <code>java</code> to work without fully-qualifying the directory:</p> -<pre><code>cat > /etc/profile.d/oracle_jdk <<'ORACLE_JDK' -PATH="${PATH}:/opt/jdk1.7.0_45/bin" -export PATH -ORACLE_JDK -</code></pre> -<p>(This will not affect non-interactive use; setting PATH for non-interactive -programs like build servers is beyond the scope of this document. Learn to use -your OS.)</p> -<p>Installation this way does <em>not</em> interact with the alternatives system (but -you can set that up by hand if you need to).</p> -<p>For tools that cannot autodetect the JDK via <code>PATH</code>, you may need to set -<code>JAVA_HOME</code> to <code>/opt/jdk1.7.0_45</code>.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/java/install/ubuntu.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/java/install/ubuntu.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/java/kwargs.html b/.html/java/kwargs.html deleted file mode 100644 index 64cc16b..0000000 --- a/.html/java/kwargs.html +++ /dev/null @@ -1,223 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Keyword Arguments in Java - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">java</a> - - </li> - - <li class="crumb-2 last"> - - kwargs - - </li> - - </ol> - - - - <div id="article"> - <h1 id="keyword-arguments-in-java">Keyword Arguments in Java</h1> -<h2 id="what">What</h2> -<p>Java arguments are traditionally passed by position:</p> -<pre><code>void foo(int x, int y, int z) -</code></pre> -<p>matches the call</p> -<pre><code>foo(1, 2, 3) -</code></pre> -<p>and assigns <code>1</code> to <code>x</code>, <code>2</code> to <code>y</code>, and <code>3</code> to <code>z</code> in the resulting -activation. Keyword arguments assign values to formal parameters by matching -the parameter's name, instead.</p> -<h2 id="why">Why</h2> -<p>Fuck the builder pattern, okay? Patterns like</p> -<pre><code>Response r = Response - .status(200) - .entity(foo) - .header("X-Plane", "Amazing") - .build(); -</code></pre> -<p>(from JAX-RS) mean the creation and maintenance of an entire separate type -just to handle arbitrary ordering and presence/absence of options. Ordering -can be done using keywords; presence/absence can be done by providing one -method for each legal combination of arguments (or by adding optional -arguments to Java).</p> -<p>The keyword-argument version would be something like</p> -<pre><code>Response r = new Response( - .status = 200, - .entity = foo, - .headers = Arrays.asList(Header.of("X-Plane", "Amazing")) -); -</code></pre> -<p>and the <code>ResponseBuilder</code> class would not need to exist at all for this case. -(There are others in JAX-RS that would still make <code>ResponseBuilder</code> mandatory, -but the use case for it gets much smaller.)</p> -<p>As an added bonus, the necessary class metadata to make this work would also -allow reflective frameworks such as Spring to make sensible use of the -parameter names:</p> -<pre><code><bean class="com.example.Person"> - <constructor-arg name="name" value="Erica McKenzie" /> -</bean> -</code></pre> -<h2 id="other-languages">Other Languages</h2> -<p>Python, most recently:</p> -<pre><code>def foo(x, y, z): - pass - -foo(z=3, x=1, y=2) -</code></pre> -<p>Smalltalk (and ObjectiveC) use an interleaving convention that reads very much -like keyword arguments:</p> -<pre><code>Point atX: 5 atY: 8 -</code></pre> -<h2 id="challenges">Challenges</h2> -<ul> -<li>Minimize changes to syntax.<ul> -<li>Make keyword arguments unambiguous.</li> -</ul> -</li> -<li>Minimize changes to bytecode spec.</li> -</ul> -<h2 id="proposal">Proposal</h2> -<p>Given a method definition</p> -<pre><code>void foo(int x, int y, int z) -</code></pre> -<p>Allow calls written as</p> -<pre><code>foo( - SOME-SYNTAX(x, EXPR), - SOME-SYNTAX(y, EXPR), - SOME-SYNTAX(z, EXPR) -) -</code></pre> -<p><code>SOME-SYNTAX</code> is a production that is not already legal at that point in Java, -which is a surprisingly frustrating limitation. Constructs like</p> -<pre><code>foo(x = EXPR, y = EXPR, z = EXPR) -</code></pre> -<p>are already legal (assignment is an expression) and already match positional -arguments.</p> -<p>Keyword arguments match the name of the formal argument in the method -declaration. Passing a keyword argument that does not match a formal argument -is a compilation error.</p> -<p>Calls can mix keyword arguments and positional arguments, in the following -order:</p> -<ol> -<li>Positional arguments.</li> -<li>Varargs positional arguments.</li> -<li>Keyword arguments.</li> -</ol> -<p>Passing the same argument as both a positional and a keyword argument is a -compilation error.</p> -<p>Call sites must satisfy every argument the method/constructor has (i.e., this -doesn't imply optional arguments). This makes implementation easy and -unintrusive: the compiler can implement keyword arguments by transforming them -into positional arguments. Reflective calls (<code>Method.invoke</code> and friends) can -continue accepting arguments as a sequence.</p> -<p>The <code>Method</code> class would expose a new method:</p> -<pre><code>public List<String> getArgumentNames() -</code></pre> -<p>The indexes in <code>getArgumentNames</code> match the indexes in <code>getArgumentTypes</code> and -related methods.</p> -<p>Possibilities for syntax:</p> -<ul> -<li> -<p><code>foo(x := 5, y := 8, z := 2)</code> - <code>:=</code> is never a legal sequence of tokens in - Java. Introduces one new operator-like construct; the new sequence <code>:=</code> - “looks like” assignment, which is a useful mnemonic.</p> -</li> -<li> -<p><code>foo(x ~ 5, y ~ 8, z ~ 2)</code> - <code>~</code> is not a binary operator and this is never - legal right now. This avoids introducing new operators, but adds a novel - interpretation to an existing unary operator that's not related to its - normal use.</p> -</li> -<li> -<p><code>foo(.x = 5, .y = 8, .z = 2)</code> - using <code>=</code> as the keyword binding feels more - natural. Parameter names must be legal identifiers, which means the leading - dot is unambiguous. This syntax is not legal anywhere right now (the dot - always has a leading expression). The dot is a “namespace” symbol already.</p> -</li> -</ul> -<p>To support this, the class file format will need to record the names of -parameters, not just their order. This is a breaking change, and generated -names will need to be chosen for existing class files. (This may be derivable -from debug information, where present.)</p> -<h2 id="edge-cases">Edge Cases</h2> -<ul> -<li>Mixed positional and keyword arguments.<ul> -<li>Collisions (same argument passed by both) are, I think, detectable at - compile time. This should be an error.</li> -</ul> -</li> -<li>Inheritance. It is legal for a superclass to define <code>foo(a, b)</code> and for - subclasses to override it as <code>foo(x, y)</code>. Which argument names do you use - when?</li> -<li>Varargs.</li> -</ul> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/java/kwargs.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/java/kwargs.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/java/stop-using-class-dot-forname.html b/.html/java/stop-using-class-dot-forname.html deleted file mode 100644 index 85190e8..0000000 --- a/.html/java/stop-using-class-dot-forname.html +++ /dev/null @@ -1,155 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Stop Using Class Dot Forname - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">java</a> - - </li> - - <li class="crumb-2 last"> - - stop-using-class-dot-forname - - </li> - - </ol> - - - - <div id="article"> - <h1 id="jdbc-drivers-and-classforname">JDBC Drivers and <code>Class.forName()</code></h1> -<p>The short version: stop using <code>Class.forName(driverClass)</code> to load JDBC -drivers. You don't need this, and haven't since Java 6. You arguably never -needed this.</p> -<p>This pattern appears all over the internet, and it's wrong.</p> -<h2 id="backstory">Backstory</h2> -<p>JDBC has more or less always provided two ways to set up <code>Connection</code> objects:</p> -<ol> -<li> -<p>Obtain them from a driver-provided <code>DataSource</code> class, which applications or - containers are expected to create for themselves.</p> -</li> -<li> -<p>Obtain them by passing a URL to <code>DriverManager</code>.</p> -</li> -</ol> -<p>Most people start with the latter, since it's very straightforward to use. -However, <code>DriverManager</code> needs to be able to locate <code>Driver</code> subclasses, and -the JVM doesn't permit class enumeration at runtime.</p> -<p>In the original JDBC release, <code>Driver</code> subclasses were expected to register -themselves on load, similar to</p> -<pre><code>public class ExampleDriver extends Driver { - static { - DriverManager.registerDriver(ExampleDriver.class); - } -} -</code></pre> -<p>Obviously, applications <em>can</em> force drivers to load using -<code>Class.forName(driverName)</code>, but this hasn't ever been the only way to do it. -<code>DriverManager</code> also provides <a href="https://docs.oracle.com/javase/8/docs/api/java/sql/DriverManager.html">a mechanism to load a set of named classes at -startup</a>, -via the <code>jdbc.drivers</code> <a href="http://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html">system property</a>.</p> -<h2 id="jdbc-4-fixed-that">JDBC 4 Fixed That</h2> -<p>JDBC 4, which came out with Java 6 in the Year of our Lord <em>Two Thousand and -Six</em>, also loads drivers using the <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html#Service%20Provider">service -provider</a> -system, which requires no intervention at all from deployers or application -developers.</p> -<p><em>You don't need to write any code to load a JDBC 4 driver.</em></p> -<h2 id="whats-the-harm">What's The Harm?</h2> -<p>It's harmless in the immediate sense: forcing a driver to load immediately -before JDBC would load it itself has no additional side effects. However, it's -a pretty clear indicator that you've copied someone else's code without -thoroughly understanding what it does, which is a bad habit.</p> -<h2 id="but-what-about-my-database">But What About My Database?</h2> -<p>You don't need to worry about it. All of the following drivers support JDBC -4-style automatic discovery:</p> -<ul> -<li> -<p>PostgreSQL (since version 8.0-321, in 2007)</p> -</li> -<li> -<p>Firebird (since <a href="http://tracker.firebirdsql.org/browse/JDBC-140">version 2.2, in 2009</a>)</p> -</li> -<li> -<p><a href="../mysql/choose-something-else">MySQL</a> (since <a href="http://dev.mysql.com/doc/relnotes/connector-j/en/news-5-0-0.html">version 5.0, in 2005</a>)</p> -</li> -<li> -<p>H2 (since day 1, as far as I can tell)</p> -</li> -<li> -<p>Derby/JavaDB (since <a href="https://issues.apache.org/jira/browse/DERBY-930">version 10.2.1.6, in 2006</a>)</p> -</li> -<li> -<p>SQL Server (version unknown, because MSDN is archaeologically hostile)</p> -</li> -</ul> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/java/stop-using-class-dot-forname.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/java/stop-using-class-dot-forname.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/keybase.txt b/.html/keybase.txt deleted file mode 100644 index 017faf9..0000000 --- a/.html/keybase.txt +++ /dev/null @@ -1,66 +0,0 @@ -================================================================== -https://keybase.io/ojacobson --------------------------------------------------------------------- - -I hereby claim: - - * I am an admin of http://grimoire.ca - * I am ojacobson (https://keybase.io/ojacobson) on keybase. - * I have a public key with fingerprint 77BD C4F1 6EFD 607E 85AA B639 5023 2991 F10D FFD0 - -To claim this, I am signing this object: - -{ - "body": { - "key": { - "fingerprint": "77bdc4f16efd607e85aab63950232991f10dffd0", - "host": "keybase.io", - "key_id": "50232991f10dffd0", - "kid": "0101597743f43180f2b27fcb7ed12c4145ab3350112c272fab57aa76bab79f14582b0a", - "uid": "f9fa4735de81873b3b1e1caca57e8100", - "username": "ojacobson" - }, - "service": { - "hostname": "grimoire.ca", - "protocol": "http:" - }, - "type": "web_service_binding", - "version": 1 - }, - "ctime": 1421787424, - "expire_in": 157680000, - "prev": "3cefe86470406fa550e9d7fcbddd243f760151c6a849a0e4cb203091e05904d7", - "seqno": 4, - "tag": "signature" -} - -with the aforementioned key, yielding the PGP signature: - ------BEGIN PGP MESSAGE----- -Comment: GPGTools - https://gpgtools.org - -owFtkl1IVEEUx3fVijalIFKhfOhaWSk2c7/m3i1LooI+tBQrgnSbuXdGb+redfdq -qRk+RB8afRgVRh8QiH1oRUFLkOU+hG1iWOFLLxUpYYIUFBhpNVfqrXkZ5pz/+Z05 -f86ZlESPz7sjc8XZrym/B739o8RT8iS2rFEgtlkv+BuFSjp9MStYTsOhsBV0BL+A -EDENmUGVMlMFiGoKxkSVdAWIkqjrkEFgMmYCIUeosCNuBccQHKG5ls1j/BGwTB79 -j75yOgEggIqOkCwxWYIaYCIRETMIoiYUDRnKCiaSpADIXyISGSYKwhipBBOkM57W -RAIwx9VO45jOsIwkxaQa1JBEJAIpNLCBFf53CNy+tREaDuJqytX2fmzYJGIHhaYc -gYfrLIO6Hrij/JWUh61q2wrTXMNtEgrbjm3YVTxR4Tghv1vn1Idc4QFKAn8RAWIF -TW4jL6ij4YjF+X7IlYZjuUwoixBpSBblHIEeDHF4wHIVClI1wI/bhtZxpGRQRjVV -RkAGKsOKAqhuuuaYpilyw5DKvYOGijVZx4DKBhGBBHRIgaID2USCO1RN0Bb8vJOD -yzkyYpUHsVMbpkKT13fCuyjJ4/V5Zs5IcFfB45s9799+VJyc9WvxvsCh1fKM1wPx -kefp0Tu9p9Yf/fnj4zU2vyzBO3mlpfaNP3+wteEs3b3uenF0+6M1yd+L5nnfiqnx -853p8bXi5zlZ73fmtvUIiXld1z41e+5tGjNuiBl5Wy6v7Ou4uHzL0gVDD/ZXNMQL -h458WH2i4FNv88o9U7Grx4TTrZXZleuHk+m3hNKbaRvuC6tedE+Mlh593Z853neu -J3RhIHb8bWPW4omXYM+F5S3Rjrlb7/Tkdxe+q8psiidOVQ3tWpLR3tgz5rt7bNuu -ga6WhzVLvA3O5jL0LDoZq2fj+DBIjV16KHa2pmXvbcdP1Yz+pIUFw8XRibQ2VvK4 -aOOZkduvbjV9+QM= -=WPnb ------END PGP MESSAGE----- - -And finally, I am proving ownership of this host by posting or -appending to this document. - -View my publicly-auditable identity here: https://keybase.io/ojacobson - -================================================================== diff --git a/.html/media/_list.html b/.html/media/_list.html deleted file mode 100644 index 14d4f1f..0000000 --- a/.html/media/_list.html +++ /dev/null @@ -1,92 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /media - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">media</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /media</code></h1> - - - <div id="directories"> - <h2>Directories</h2> - <ul> - - <li><a href="css/">css/</a></li> - - <li><a href="dev/">dev/</a></li> - - <li><a href="email/">email/</a></li> - - </ul> - </div> - - - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/media">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/media/css/_list.html b/.html/media/css/_list.html deleted file mode 100644 index b17b4d1..0000000 --- a/.html/media/css/_list.html +++ /dev/null @@ -1,94 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /media/css - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="reset.css"> - <link - rel="stylesheet" - type="text/css" - href="grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="../">media</a> - - </li> - - <li class="crumb-2 not-last"> - - <a href="./">css</a> - - </li> - - <li class="crumb-3 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /media/css</code></h1> - - - - - - - <div id="files"> - <h2>Files</h2> - - <li><a href="grimoire.css">grimoire.css</a></li> - - <li><a href="reset.css">reset.css</a></li> - - </div> - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/media/css">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/media/css/grimoire.css b/.html/media/css/grimoire.css deleted file mode 100644 index e817dd4..0000000 --- a/.html/media/css/grimoire.css +++ /dev/null @@ -1,135 +0,0 @@ -/* typography */ -body { - font-family: 'Baskerville', 'Buenard', serif; - font-size: 20px; - line-height: 30px; -} - -code { - font-family: 'Menlo', monospace; - font-size: 80%; -} - -em { - font-style: italic; -} - -strong { - font-weight: bold; -} - -blockquote { - margin-left: 40px; - color: #555; -} - -:link { - text-decoration: none; -} - -hr { - border: none; - border-top: 1px solid #AAA; - margin-left: 80px; - margin-right: 80px; -} - -h1, h2, h3, h4, h5, h6 { - font-weight: bold; -} - -h1 { - font-size: 40px; - line-height: 60px; - margin-bottom: 15px; -} -h2 { - font-size: 30px; - line-height: 45px; - margin-bottom: 15px; -} -h3 { - font-size: 20px; - line-height: 30px; - margin-bottom: 15px; -} - -/* layout */ -#shell { - margin-left: auto; - margin-right: auto; - width: 840px; -} - -#shell > * { - margin-top: 15px; - margin-bottom: 15px; - padding: 0 10px; -} - -#article, -#listing { - padding-left: 50px; -} -h1, h2, h3, h4, h5, h6 { - margin-left: -40px; -} - -#article p, -#article pre, -#article ul, -#article ol, -#article dl, -#listing ul { - margin-bottom: 15px; -} - -#article pre { - margin-left: 40px; -} - -#article > p > img { - margin-left: auto; - margin-right: auto; - display: block; -} - -#article ul { - list-style-type: disc; -} -#article ol { - list-style-type: decimal; -} - -#article ul, -#article ol, -#article dl { - padding-left: 40px; -} - -#article dd { - padding-left: 40px; -} - -#breadcrumbs li { - display: inline-block; -} -#breadcrumbs li.not-last:after { - content: '•'; -} - -@media print { - #breadcrumbs, - #comments, - #footer { - display: none; - } - - a:link { - color: black; - } - :link:after { - content: " (" attr(href) ")"; - font-size: 16px; - } -}
\ No newline at end of file diff --git a/.html/media/css/index.html b/.html/media/css/index.html deleted file mode 100644 index b17b4d1..0000000 --- a/.html/media/css/index.html +++ /dev/null @@ -1,94 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /media/css - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="reset.css"> - <link - rel="stylesheet" - type="text/css" - href="grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="../">media</a> - - </li> - - <li class="crumb-2 not-last"> - - <a href="./">css</a> - - </li> - - <li class="crumb-3 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /media/css</code></h1> - - - - - - - <div id="files"> - <h2>Files</h2> - - <li><a href="grimoire.css">grimoire.css</a></li> - - <li><a href="reset.css">reset.css</a></li> - - </div> - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/media/css">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/media/css/reset.css b/.html/media/css/reset.css deleted file mode 100644 index e29c0f5..0000000 --- a/.html/media/css/reset.css +++ /dev/null @@ -1,48 +0,0 @@ -/* http://meyerweb.com/eric/tools/css/reset/ - v2.0 | 20110126 - License: none (public domain) -*/ - -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, canvas, details, embed, -figure, figcaption, footer, header, hgroup, -menu, nav, output, ruby, section, summary, -time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; -} -/* HTML5 display-role reset for older browsers */ -article, aside, details, figcaption, figure, -footer, header, hgroup, menu, nav, section { - display: block; -} -body { - line-height: 1; -} -ol, ul { - list-style: none; -} -blockquote, q { - quotes: none; -} -blockquote:before, blockquote:after, -q:before, q:after { - content: ''; - content: none; -} -table { - border-collapse: collapse; - border-spacing: 0; -} diff --git a/.html/media/dev/_list.html b/.html/media/dev/_list.html deleted file mode 100644 index 28020c6..0000000 --- a/.html/media/dev/_list.html +++ /dev/null @@ -1,96 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /media/dev - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="../">media</a> - - </li> - - <li class="crumb-2 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-3 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /media/dev</code></h1> - - - <div id="directories"> - <h2>Directories</h2> - <ul> - - <li><a href="builds/">builds/</a></li> - - <li><a href="merging-structural-changes/">merging-structural-changes/</a></li> - - </ul> - </div> - - - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/media/dev">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/media/dev/builds/_list.html b/.html/media/dev/builds/_list.html deleted file mode 100644 index 8af9c54..0000000 --- a/.html/media/dev/builds/_list.html +++ /dev/null @@ -1,98 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /media/dev/builds - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../../css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../../css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../../../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="../../">media</a> - - </li> - - <li class="crumb-2 not-last"> - - <a href="../">dev</a> - - </li> - - <li class="crumb-3 not-last"> - - <a href="./">builds</a> - - </li> - - <li class="crumb-4 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /media/dev/builds</code></h1> - - - - - - - <div id="files"> - <h2>Files</h2> - - <li><a href="buildifesto-pyramid.png">buildifesto-pyramid.png</a></li> - - </div> - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/media/dev/builds">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/media/dev/builds/buildifesto-pyramid.png b/.html/media/dev/builds/buildifesto-pyramid.png Binary files differdeleted file mode 100644 index a06148e..0000000 --- a/.html/media/dev/builds/buildifesto-pyramid.png +++ /dev/null diff --git a/.html/media/dev/builds/index.html b/.html/media/dev/builds/index.html deleted file mode 100644 index 8af9c54..0000000 --- a/.html/media/dev/builds/index.html +++ /dev/null @@ -1,98 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /media/dev/builds - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../../css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../../css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../../../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="../../">media</a> - - </li> - - <li class="crumb-2 not-last"> - - <a href="../">dev</a> - - </li> - - <li class="crumb-3 not-last"> - - <a href="./">builds</a> - - </li> - - <li class="crumb-4 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /media/dev/builds</code></h1> - - - - - - - <div id="files"> - <h2>Files</h2> - - <li><a href="buildifesto-pyramid.png">buildifesto-pyramid.png</a></li> - - </div> - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/media/dev/builds">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/media/dev/index.html b/.html/media/dev/index.html deleted file mode 100644 index 28020c6..0000000 --- a/.html/media/dev/index.html +++ /dev/null @@ -1,96 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /media/dev - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="../">media</a> - - </li> - - <li class="crumb-2 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-3 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /media/dev</code></h1> - - - <div id="directories"> - <h2>Directories</h2> - <ul> - - <li><a href="builds/">builds/</a></li> - - <li><a href="merging-structural-changes/">merging-structural-changes/</a></li> - - </ul> - </div> - - - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/media/dev">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/media/dev/merging-structural-changes/_list.html b/.html/media/dev/merging-structural-changes/_list.html deleted file mode 100644 index bbdf659..0000000 --- a/.html/media/dev/merging-structural-changes/_list.html +++ /dev/null @@ -1,102 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /media/dev/merging-structural-changes - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../../css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../../css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../../../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="../../">media</a> - - </li> - - <li class="crumb-2 not-last"> - - <a href="../">dev</a> - - </li> - - <li class="crumb-3 not-last"> - - <a href="./">merging-structural-changes</a> - - </li> - - <li class="crumb-4 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /media/dev/merging-structural-changes</code></h1> - - - - - - - <div id="files"> - <h2>Files</h2> - - <li><a href="ideal-merge-results.png">ideal-merge-results.png</a></li> - - <li><a href="mercurial-merge-results.png">mercurial-merge-results.png</a></li> - - <li><a href="subversion-merge-results.png">subversion-merge-results.png</a></li> - - </div> - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/media/dev/merging-structural-changes">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/media/dev/merging-structural-changes/ideal-merge-results.png b/.html/media/dev/merging-structural-changes/ideal-merge-results.png Binary files differdeleted file mode 100644 index cb78110..0000000 --- a/.html/media/dev/merging-structural-changes/ideal-merge-results.png +++ /dev/null diff --git a/.html/media/dev/merging-structural-changes/index.html b/.html/media/dev/merging-structural-changes/index.html deleted file mode 100644 index bbdf659..0000000 --- a/.html/media/dev/merging-structural-changes/index.html +++ /dev/null @@ -1,102 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /media/dev/merging-structural-changes - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../../css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../../css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../../../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="../../">media</a> - - </li> - - <li class="crumb-2 not-last"> - - <a href="../">dev</a> - - </li> - - <li class="crumb-3 not-last"> - - <a href="./">merging-structural-changes</a> - - </li> - - <li class="crumb-4 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /media/dev/merging-structural-changes</code></h1> - - - - - - - <div id="files"> - <h2>Files</h2> - - <li><a href="ideal-merge-results.png">ideal-merge-results.png</a></li> - - <li><a href="mercurial-merge-results.png">mercurial-merge-results.png</a></li> - - <li><a href="subversion-merge-results.png">subversion-merge-results.png</a></li> - - </div> - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/media/dev/merging-structural-changes">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/media/dev/merging-structural-changes/mercurial-merge-results.png b/.html/media/dev/merging-structural-changes/mercurial-merge-results.png Binary files differdeleted file mode 100644 index d20f360..0000000 --- a/.html/media/dev/merging-structural-changes/mercurial-merge-results.png +++ /dev/null diff --git a/.html/media/dev/merging-structural-changes/subversion-merge-results.png b/.html/media/dev/merging-structural-changes/subversion-merge-results.png Binary files differdeleted file mode 100644 index 5ef2570..0000000 --- a/.html/media/dev/merging-structural-changes/subversion-merge-results.png +++ /dev/null diff --git a/.html/media/email/_list.html b/.html/media/email/_list.html deleted file mode 100644 index f5205d6..0000000 --- a/.html/media/email/_list.html +++ /dev/null @@ -1,92 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /media/email - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="../">media</a> - - </li> - - <li class="crumb-2 not-last"> - - <a href="./">email</a> - - </li> - - <li class="crumb-3 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /media/email</code></h1> - - - - - - - <div id="files"> - <h2>Files</h2> - - <li><a href="flowchart.png">flowchart.png</a></li> - - </div> - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/media/email">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/media/email/flowchart.png b/.html/media/email/flowchart.png Binary files differdeleted file mode 100644 index a3f5ef0..0000000 --- a/.html/media/email/flowchart.png +++ /dev/null diff --git a/.html/media/email/index.html b/.html/media/email/index.html deleted file mode 100644 index f5205d6..0000000 --- a/.html/media/email/index.html +++ /dev/null @@ -1,92 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /media/email - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="../">media</a> - - </li> - - <li class="crumb-2 not-last"> - - <a href="./">email</a> - - </li> - - <li class="crumb-3 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /media/email</code></h1> - - - - - - - <div id="files"> - <h2>Files</h2> - - <li><a href="flowchart.png">flowchart.png</a></li> - - </div> - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/media/email">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/media/index.html b/.html/media/index.html deleted file mode 100644 index 14d4f1f..0000000 --- a/.html/media/index.html +++ /dev/null @@ -1,92 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /media - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">media</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /media</code></h1> - - - <div id="directories"> - <h2>Directories</h2> - <ul> - - <li><a href="css/">css/</a></li> - - <li><a href="dev/">dev/</a></li> - - <li><a href="email/">email/</a></li> - - </ul> - </div> - - - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/media">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/muds/_list.html b/.html/muds/_list.html deleted file mode 100644 index a36d276..0000000 --- a/.html/muds/_list.html +++ /dev/null @@ -1,88 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /muds - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">muds</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /muds</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="tinyfugue-on-yosemite">Compiling TinyFugue on Yosemite</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/muds">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/muds/index.html b/.html/muds/index.html deleted file mode 100644 index a36d276..0000000 --- a/.html/muds/index.html +++ /dev/null @@ -1,88 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /muds - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">muds</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /muds</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="tinyfugue-on-yosemite">Compiling TinyFugue on Yosemite</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/muds">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/muds/tinyfugue-on-yosemite.html b/.html/muds/tinyfugue-on-yosemite.html deleted file mode 100644 index d5c6a32..0000000 --- a/.html/muds/tinyfugue-on-yosemite.html +++ /dev/null @@ -1,106 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Compiling TinyFugue on Yosemite - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">muds</a> - - </li> - - <li class="crumb-2 last"> - - tinyfugue-on-yosemite - - </li> - - </ol> - - - - <div id="article"> - <h1 id="compiling-tinyfugue-on-yosemite">Compiling TinyFugue on Yosemite</h1> -<p>TinyFugue's site claims that it works on OS X. This is largely true, but the -switch from <code>gcc</code> to <code>clang</code> has eliminated support for some <em>deeply</em> legacy -symbols.</p> -<p>Since SourceForge is a death zone, I'll post my fix here. To get TinyFugue to -compile, apply the following patch:</p> -<pre><code>--- src/malloc.c.orig 2015-02-13 23:45:44.000000000 -0500 -+++ src/malloc.c 2015-02-13 23:45:28.000000000 -0500 -@@ -12,7 +12,6 @@ - #include "signals.h" - #include "malloc.h" - --caddr_t mmalloc_base = NULL; - int low_memory_warning = 0; - static char *reserve = NULL; -</code></pre> -<p>This symbol appears to be unused. Certainly I haven't been able to find any -references, and <code>tf</code> works well enough.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/muds/tinyfugue-on-yosemite.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/muds/tinyfugue-on-yosemite.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/mysql/_list.html b/.html/mysql/_list.html deleted file mode 100644 index 6a60e6b..0000000 --- a/.html/mysql/_list.html +++ /dev/null @@ -1,90 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /mysql - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">mysql</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /mysql</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="choose-something-else">Do Not Pass This Way Again</a></li> - - <li><a href="broken-xa">MySQL's Two-Phase Commit Implementation Is Broken</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/mysql">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/mysql/broken-xa.html b/.html/mysql/broken-xa.html deleted file mode 100644 index b9a3568..0000000 --- a/.html/mysql/broken-xa.html +++ /dev/null @@ -1,115 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - MySQL's Two-Phase Commit Implementation Is Broken - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">mysql</a> - - </li> - - <li class="crumb-2 last"> - - broken-xa - - </li> - - </ol> - - - - <div id="article"> - <h1 id="mysqls-two-phase-commit-implementation-is-broken">MySQL's Two-Phase Commit Implementation Is Broken</h1> -<p>From <a href="http://dev.mysql.com/doc/refman/5.5/en/xa-restrictions.html">the fine -manual</a>:</p> -<blockquote> -<p>If an XA transaction has reached the PREPARED state and the MySQL server is -killed (for example, with kill -9 on Unix) or shuts down abnormally, the -transaction can be continued after the server restarts. However, if the -client reconnects and commits the transaction, the transaction will be -absent from the binary log even though it has been committed. This means the -data and the binary log have gone out of synchrony. An implication is that -<strong>XA cannot be used safely together with replication</strong>.</p> -</blockquote> -<p>(Emphasis mine.)</p> -<p>If you're solving the kinds of problems where two-phase commit and XA -transaction management look attractive, then you very likely have the kinds of -uptime requirements that make replication mandatory. “It works, but not with -replication” is effectively “it doesn't work.”</p> -<blockquote> -<p>It is possible that the server will roll back a pending XA transaction, even -one that has reached the PREPARED state. This happens if a client connection -terminates and the server continues to run, or if clients are connected and -the server shuts down gracefully.</p> -</blockquote> -<p>XA transaction managers assume that if every resource successfully reaches the -PREPARED state, then every resource will be able to commit the transaction -“eventually.” Resources that unilaterally roll back PREPARED transactions -violate this assumption pretty badly.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/mysql/broken-xa.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/mysql/broken-xa.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/mysql/choose-something-else.html b/.html/mysql/choose-something-else.html deleted file mode 100644 index ca3a7b2..0000000 --- a/.html/mysql/choose-something-else.html +++ /dev/null @@ -1,836 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Do Not Pass This Way Again - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">mysql</a> - - </li> - - <li class="crumb-2 last"> - - choose-something-else - - </li> - - </ol> - - - - <div id="article"> - <h1 id="do-not-pass-this-way-again">Do Not Pass This Way Again</h1> -<p>Considering MySQL? Use something else. Already on MySQL? Migrate. For every -successful project built on MySQL, you could uncover a history of time wasted -mitigating MySQL's inadequacies, masked by a hard-won, but meaningless, sense -of accomplishment over the effort spent making MySQL behave.</p> -<p>Thesis: databases fill roles ranging from pure storage to complex and -interesting data processing; MySQL is differently bad at both tasks. Real apps -all fall somewhere between these poles, and suffer variably from both sets of -MySQL flaws.</p> -<ul> -<li>MySQL is bad at <a href="#storage">storage</a>.</li> -<li>MySQL is bad at <a href="#data-processing">data processing</a>.</li> -<li>MySQL is bad <a href="#by-design">by design</a>.</li> -<li><a href="#bad-arguments">Bad arguments</a> for using MySQL.</li> -</ul> -<p>Much of this is inspired by the principles behind <a href="http://me.veekun.com/blog/2012/04/09/php-a-fractal-of-bad-design/">PHP: A Fractal of Bad -Design</a>. I -suggest reading that article too -- it's got a lot of good thought in it even -if you already know to stay well away from PHP. (If that article offends you, -well, this page probably will too.)</p> -<h2 id="storage">Storage</h2> -<p>Storage systems have four properties:</p> -<ol> -<li>Take and store data they receive from applications.</li> -<li>Keep that data safe against loss or accidental change.</li> -<li>Provide stored data to applications on demand.</li> -<li>Give administrators effective management tools.</li> -</ol> -<p>In a truly “pure” storage application, data-comprehension features -(constraints and relationships, nontrivial functions and aggregates) would go -totally unused. There is a time and a place for this: the return of “NoSQL” -storage systems attests to that.</p> -<p>Pure storage systems tend to be closely coupled to their “main” application: -consider most web/server app databases. “Secondary” clients tend to be -read-only (reporting applications, monitoring) or to be utilities in service -of the main application (migration tools, documentation tools). If you believe -constraints, validity checks, and other comprehension features can be -implemented in “the application,” you are probably thinking of databases close -to this pole.</p> -<h3 id="storing-data">Storing Data</h3> -<p>MySQL has many edge cases which reduce the predictability of its behaviour -when storing information. Most of these edge cases are documented, but violate -the principle of least surprise (not to mention the expectations of users -familiar with other SQL implementations).</p> -<ul> -<li>Implicit conversions (particularly to and from string types) can modify - MySQL's behaviour.<ul> -<li>Many implicit conversions are also silent (no warning, no diagnostic), - by design, making it more likely developers are entirely unaware of - them until one does something surprising.</li> -</ul> -</li> -<li>Conversions that violate basic constraints (range, length) of the output - type often coerce data rather than failing.<ul> -<li>Sometimes this raises a warning; does your app check for those?</li> -<li>This behaviour is unlike many typed systems (but closely like PHP and - remotely like Perl).</li> -</ul> -</li> -<li>Conversion behaviour depends on a per-connection configuration value - (<code>sql_mode</code>) that has <a href="http://dev.mysql.com/doc/refman/5.5/en/server-sql-mode.html">a large constellation of possible - states</a>, making - it harder to carry expectations from manual testing over to code or from - tool to tool.</li> -<li>MySQL recommends UTF-8 as a character-set, but still defaults to Latin-1. - The implimentation of <code>utf8</code> up until MySQL 5.5 was only the 3-byte - <a href="http://en.wikipedia.org/wiki/Basic_Multilingual_Plane#Basic_Multilingual_Plane">BMP</a>. - MySQL 5.5 and beyond supports a 4-byte <code>utf8</code>, but confusingly must be set - with the character-set <code>utf8mb4</code>. Implementation details of these encodings - within MySQL, such as the <code>utf8</code> 3-byte limit, tend to leak out into client - applications. Data that does not fit MySQL's understanding of the storage - encoding will be transformed until it does, by truncation or replacement, by - default.<ul> -<li>Collation support is per-encoding, with one of the stranger default - configurations: by default, the collation orders characters according to - Swedish alphabetization rules, case-insensitively.</li> -<li>Since it's the default, lots of folks who don't know the manual - inside-out and backwards observe MySQL's case-insensitive collation - behaviour (<code>'a' = 'A'</code>) and conclude that “MySQL is case-insensitive,” - complicating any effort to use a case-sensitive locale.</li> -<li>Both the encoding and the collation can vary, independently, by - <em>column</em>. Do you keep your schema definition open when you write - queries to watch out for this sort of shit?</li> -</ul> -</li> -<li>The <code>TIMESTAMP</code> type tries to do something smart by storing values in a - canonical timezone (UTC), but it's done with so few affordances that it's - very hard to even <em>tell</em> that MySQL's done a right thing with your data.<ul> -<li>And even after that, the result of <code>foo < '2012-04-01 09:00:00'</code> still - depends on what time of year it is when you evaluate the query, unless - you're very careful with your connection timezone.</li> -<li><code>TIMESTAMP</code> is also special-cased in MySQL's schema definition handling, - making it easy to accidentally create (or to accidentally fail to - create) an auto-updating field when you didn't (did) want one.</li> -<li><code>DATETIME</code> does not get the same timezone handling <code>TIMESTAMP</code> does. - What? And you can't provide your own without resorting to hacks like - extra columns.</li> -<li>Oh, did you want to <em>use</em> MySQL's timezone support? Too bad, none of - that data's loaded by default. You have to process the OS's <code>tzinfo</code> - files into SQL with a separate tool and import that. If you ever want to - update MySQL's timezone settings later, you need to take the server down - just to make sure the changes apply.</li> -</ul> -</li> -</ul> -<h3 id="preserving-data">Preserving Data</h3> -<p>... against unexpected changes: like most disk-backed storage systems, MySQL -is as reliable as the disks and filesystems its data lives on. MySQL provides -no additional functionality in terms of mirroring or hardware failure tolerance -(such as <a href="http://en.wikipedia.org/wiki/Automatic_Storage_Management">Oracle ASM</a>). -However this is a limitation shared with many, <em>many</em> other systems.</p> -<p>When using the InnoDB storage engine (default since MySQL 5.5), MySQL maintains page -checksums in order to detect corruption caused by underlying storage. However, -many third-party software applications, as sell as users upgrading -from earlier versions of MySQL may be using MyISAM, which will frequently corrupt -data files on improper shutdown.</p> -<p>The implicit conversion rules that bite when storing data also bite when -asking MySQL to modify data - my favourite example being a fat-fingered -<code>UPDATE</code> query where a mistyped <code>=</code> (as <code>-</code>, off by a single key) caused 90% -of the rows in the table to be affected, instead of one row, because of -implicit string-to-integer conversions.</p> -<p>... against loss: hoo boy. MySQL, out of the box, gives you three approaches -to <a href="http://dev.mysql.com/doc/refman/5.5/en/backup-methods.html">backups</a>:</p> -<ul> -<li>Take “blind” filesystem backups with <code>tar</code> or <code>rsync</code>. Unless you - meticulously lock tables or make the database read-only for the duration, - this produces a backup that requires crash recovery before it will be - usable, and can produce an inconsistent database.<ul> -<li>This can bite quite hard if you use InnoDB, as InnoDB crash recovery - takes time proportional to both the number of InnoDB tables and the - total size of InnoDB tables, with a large constant.</li> -</ul> -</li> -<li>Dump to SQL with <code>mysqldump</code>: slow, relatively large backups, and - non-incremental.</li> -<li>Archive binary logs: fragile, complex, over-configurable, and configured - badly by default. (Binary logging is also the basis of MySQL's replication - system.)</li> -</ul> -<p>If neither of these are sufficient, you're left with purchasing <a href="http://dev.mysql.com/doc/refman/5.5/en/glossary.html#glos_mysql_enterprise_backup">a backup tool -from -Oracle</a> -or from one of the third-party MySQL vendors.</p> -<p>Like many of MySQL's features, the binary logging feature is -<a href="http://dev.mysql.com/doc/refman/5.5/en/binary-log.html">too</a> -<a href="http://dev.mysql.com/doc/refman/5.5/en/replication-options-binary-log.html">configurable</a>, -while still, somehow, defaulting to modes that are hazardous or surprising: -the -<a href="http://dev.mysql.com/doc/refman/5.5/en/replication-options-binary-log.html#sysvar_binlog_format">default</a> -<a href="http://dev.mysql.com/doc/refman/5.5/en/replication-formats.html">behaviour</a> -is to log SQL statements, rather than logging their side effects. This has -lead to numerous bugs over the years; MySQL (now) makes an effort to make -common “non-deterministic” cases such as <code>NOW()</code> and <code>RANDOM()</code> act -deterministically but these have been addressed using ad-hoc solutions. -Restoring binary-log-based backups can easily lead to data that differs from -the original system, and by the time you've noticed the problem, it's too late -to do anything about it.</p> -<p>(Seriously. The binary log entries for each statement contain the “current” -time on the master and the random seed at the start of the statement, just in -case. If your non-deterministic query uses any other function, you're still -<a href="http://dev.mysql.com/doc/refman/5.5/en/replication-sbr-rbr.html#replication-sbr-rbr-sbr-disadvantages">fucked by -default</a>.)</p> -<p>Additionally, a number of apparently-harmless features can lead to backups or -replicas wandering out of sync with the original database, in the default -configuration:</p> -<ul> -<li><code>AUTO_INCREMENT</code> and <code>UPDATE</code> statements.</li> -<li><code>AUTO_INCREMENT</code> and <code>INSERT</code> statements (sometimes). SURPRISE.</li> -<li>Triggers.</li> -<li>User-defined (native) functions.</li> -<li>Stored (procedural SQL) functions.</li> -<li><code>DELETE ... LIMIT</code> and <code>UPDATE ... LIMIT</code> statements, though if you use - these, you've misunderstood how SQL is supposed to work.</li> -<li><code>INSERT ... ON DUPLICATE KEY UPDATE</code> statements.</li> -<li>Bulk-loading data with <code>LOAD DATA</code> statements.</li> -<li><a href="http://dev.mysql.com/doc/refman/5.5/en/replication-features-floatvalues.html">Operations on floating-point - values</a>.</li> -</ul> -<h3 id="retrieving-data">Retrieving Data</h3> -<p>This mostly works as expected. Most of the ways MySQL will screw you happen -when you store data, not when you retrieve it. However, there are a few things -that implicitly transform stored data before returning it:</p> -<ul> -<li> -<p>MySQL's surreal type conversion system works the same way during <code>SELECT</code> - that it works during other operations, which can lead to queries matching - unexpected rows:</p> -<pre><code>owen@scratch> CREATE TABLE account ( - -> accountid INTEGER - -> AUTO_INCREMENT - -> PRIMARY KEY, - -> discountid INTEGER - -> ); -Query OK, 0 rows affected (0.54 sec) - -owen@scratch> INSERT INTO account - -> (discountid) - -> VALUES - -> (0), - -> (1), - -> (2); -Query OK, 3 rows affected (0.03 sec) -Records: 3 Duplicates: 0 Warnings: 0 - -owen@scratch> SELECT * - -> FROM account - -> WHERE discountid = 'banana'; -+-----------+------------+ -| accountid | discountid | -+-----------+------------+ -| 1 | 0 | -+-----------+------------+ -1 row in set, 1 warning (0.05 sec) -</code></pre> -<p>Ok, unexpected, but there's at least a warning (do your apps check for -those?) - let's see what it says:</p> -<pre><code>owen@scratch> SHOW WARNINGS; -+---------+------+--------------------------------------------+ -| Level | Code | Message | -+---------+------+--------------------------------------------+ -| Warning | 1292 | Truncated incorrect DOUBLE value: 'banana' | -+---------+------+--------------------------------------------+ -1 row in set (0.03 sec) -</code></pre> -<p>I can count on one hand the number of <code>DOUBLE</code> columns in this example and -still have five fingers left over.</p> -<p>You might think this is an unreasonable example: maybe you should always -make sure your argument types exactly match the field types, and the query -should use <code>57</code> instead of <code>'banana'</code>. (This does actually “fix” the -problem.) It's unrealistic to expect every single user to run <code>SHOW CREATE -TABLE</code> before every single query, or to memorize the types of every column -in your schema, though. This example derived from a technically-skilled -but MySQL-ignorant tester examining MySQL data to verify some behavioural -changes in an app.</p> -<ul> -<li> -<p>Actually, you don't even need a table for this: <code>SELECT 0 = 'banana'</code> - returns <code>1</code>. Did the <a href="http://phpsadness.com/sad/52">PHP</a> folks design - MySQL's <code>=</code> operator?</p> -</li> -<li> -<p>This isn't affected by <code>sql_mode</code>, even though so many other things are.</p> -</li> -</ul> -</li> -<li> -<p><code>TIMESTAMP</code> columns (and <em>only</em> <code>TIMESTAMP</code> columns) can return - apparently-differing values for the same stored value depending on - per-connection configuration even during read-only operation. This is done - silently and the default behaviour can change as a side effect of non-MySQL - configuration changes in the underlying OS.</p> -</li> -<li>String-typed columns are transformed for encoding on output if the - connection is not using the same encoding as the underlying storage, using - the same rules as the transformation on input.</li> -<li>Values that stricter <code>sql_mode</code> settings would reject during storage can - still be returned during retrieval; it is impossible to predict in advance - whether such data exists, since clients are free to set <code>sql_mode</code> to any - value at any time.</li> -</ul> -<h3 id="efficiency">Efficiency</h3> -<p>For purely store-and-retrieve applications, MySQL's query planner (which -transforms the miniature program contained in each SQL statement into a tree -of disk access and data manipulation steps) is sufficient, but only barely. -Queries that retrieve data from one table, or from one table and a small -number of one-to-maybe-one related tables, produce relatively efficient plans.</p> -<p>MySQL, however, offers a number of tuning options that can have dramatic and -counterintuitive effects, and the documentation provides very little advice -for choosing settings. Tuning relies on the administrator's personal -experience, blog articles of varying quality, and consultants.</p> -<ul> -<li>The MySQL query cache defaults to a non-zero size in some commonly-installed - configurations. However, the larger the cache, the slower writes proceed: - invalidating cache entries that include the tables modified by a query means - considering every entry in the cache. This cache also uses MySQL's LRU - implementation, which has its own performance problems during eviction that - get worse with larger cache sizes.</li> -<li>Memory-management settings, including <code>key_buffer_size</code> and <code>innodb_buffer_pool_size</code>, - have non-linear relationships with performance. The <a href="http://www.mysqlperformanceblog.com/2006/09/29/what-to-tune-in-mysql-server-after-installation/">standard</a> - <a href="http://www.mysqlperformanceblog.com/2007/11/01/innodb-performance-optimization-basics/">advice</a> advises - making whichever value you care about more to a large value, but this can be - counterproductive if the related data is larger than the pool can hold: - MySQL is once again bad at discarding old buffer pages when the buffer is - exhausted, leading to dramatic slowdowns when query load reaches a certain - point.<ul> -<li>This also affects filesystem tuning settings such as <code>table_open_cache</code>.</li> -</ul> -</li> -<li>InnoDB, out of the box, comes configured to use one large (and automatically - growing) tablespace file for all tables, complicating backups and storage - management. This is fine for trivial databases, but MySQL provides no tools - (aside from <code>DROP TABLE</code> and reloading the data from an SQL dump) for - transplanting a table to another tablespace, and provides no tools (aside - from a filesystem-level <code>rm</code>, and reloading <em>all</em> InnoDB data from an SQL - dump) for reclaiming empty space in a tablespace file.</li> -<li>MySQL itself provides very few tools to manage storage; tasks like storing - large or infrequently-accessed tables and databases on dedicated filesystems - must be done on the filesystem, with MySQL shut down.</li> -</ul> -<h2 id="data-processing">Data Processing</h2> -<p>Data processing encompasses tasks that require making decisions about data and -tasks that derive new data from existing data. This is a huge range of topics:</p> -<ul> -<li>Deciding (and enforcing) application-specific validity rules.</li> -<li>Summarizing and deriving data.</li> -<li>Providing and maintaining alternate representations and structures.</li> -<li>Hosting complex domain logic near the data it operates on.</li> -</ul> -<p>The further towards data processing tasks applications move, the more their -SQL resembles tiny programs sent to the data. MySQL is totally unprepared for -programs, and expects SQL to retrieve or modify simple rows.</p> -<h3 id="validity">Validity</h3> -<p>Good constraints are like <code>assert</code>s: in an ideal world, you can't tell if they -work, because your code never violates them. Here in the real world, -constraint violations happen for all sorts of reasons, ranging from buggy code -to buggy human cognition. A good database gives you more places to describe -your expectations and more tools for detecting and preventing surprises. -MySQL, on the other hand, can't validate your data for you, beyond simple (and -fixed) type constraints:</p> -<ul> -<li> -<p>As with the data you store in it, MySQL feels free to change your table - definitions <a href="http://dev.mysql.com/doc/refman/5.5/en/silent-column-changes.html">implicitly and - silently</a>. - Many of these silent schema changes have important performance and - feature-availability implications.</p> -<ul> -<li> -<p>Foreign keys are ignored if you spell them certain, common, ways:</p> -<pre><code>CREATE TABLE foo ( - -- ..., - parent INTEGER - NOT NULL - REFERENCES foo_parent (id) - -- , ... -) -</code></pre> -<p>silently ignores the foreign key specification, while</p> -<pre><code>CREATE TABLE foo ( - -- ..., - parent INTEGER - NOT NULL, - FOREIGN KEY (parent) - REFERENCES foo_parent (id) - -- , ... -) -</code></pre> -<p>preserves it.</p> -</li> -</ul> -</li> -<li> -<p>Foreign keys, one of the most widely-used database validity checks, are an - engine-specific feature, restricting their availability in combination with - other engine-specific features. (For example, a table cannot have both - foreign key constraints and full-text indexes, as of MySQL 5.5.)</p> -<ul> -<li>Configurations that violate assumptions about foreign keys, such as a - foreign key pointing into a MyISAM or NDB table, do not cause warnings - or any other diagnostics. The foreign key is simply discarded. SURPRISE. - (MySQL is riddled with these sorts of surprises, and apologists lean - very heavily on the “that's documented” excuse for its bad behaviour.)</li> -</ul> -</li> -<li>The MySQL parser recognizes <code>CHECK</code> clauses, which allow schema developers - to make complex declarative assertions about tuples in the database, but - <a href="http://dev.mysql.com/doc/refman/5.5/en/create-table.html">discards them without - warning</a>. If you - want <code>CHECK</code>-like constraints, you must implement them as triggers - but see - below...</li> -<li>MySQL's comprehension of the <code>DEFAULT</code> clause is, uh, limited: only - constants are permitted, except for the <a href="https://dev.mysql.com/doc/refman/5.5/en/timestamp-initialization.html">special - case</a> - of at most one <code>TIMESTAMP</code> column per table and at most one sequence-derived - column. Who designed this mess?<ul> -<li>Furthermore, there's no way to say “no default” and raise an error when - an INSERT forgets to provide a value. The default <code>DEFAULT</code> is either - <code>NULL</code> or a zero-like constant (<code>0</code>, <code>''</code>, and so on). Even for types - with no meaningful zero-like values (<code>DATETIME</code>).</li> -</ul> -</li> -<li>MySQL has no mechanism for introducing new types, which might otherwise - provide a route to enforcing validity. Counting the number of special cases - in MySQL's <a href="http://dev.mysql.com/doc/refman/5.5/en/data-types.html">existing type - system</a> illustrates - why that's probably unfixable.</li> -</ul> -<p>I hope every client with write access to your data is absolutely perfect, -because MySQL <em>cannot help you</em> if you make a mistake.</p> -<h3 id="summarizing-and-deriving-data">Summarizing and Deriving Data</h3> -<p>SQL databases generally provide features for doing “interesting” things with -sets of tuples, and MySQL is no exception. However, MySQL's limitations mean -that actually processing data in the database is fraught with wasted money, -brains, and time:</p> -<ul> -<li>Aggregate (<code>GROUP BY</code>) queries run up against limits in MySQL's query - planner: a query with both <code>WHERE</code> and <code>GROUP BY</code> clauses can only satisfy - one constraint or the other with indexes, unless there's an index that - covers all the relevant fields in both clauses, in the right order. (What - this order is depends on the complexity of the query and on the distribution - of the underlying data, but that's hardly MySQL-specific.)<ul> -<li>If you have all three of <code>WHERE</code>, <code>GROUP BY</code>, and <code>ORDER BY</code> in the same - query, you're more or less fucked. Good luck designing a single index - that satisfies all three.</li> -</ul> -</li> -<li>Even though MySQL allows database administrators to <a href="http://dev.mysql.com/doc/refman/5.5/en/create-procedure.html">define normal functions - in a procedural SQL - dialect</a>, - <a href="http://dev.mysql.com/doc/refman/5.5/en/create-function-udf.html">custom aggregate - functions</a> - can only be defined by native plugins. Good thing, too, because procedural - SQL in MySQL is its own kind of awful - more on that below.</li> -<li>Subqueries are often convenient and occasionally necessary for expressing - multi-step transformations on some underlying data. MySQL's query planner - has only one strategy for optimizing them: evaluate the innermost query as - written, into an in-memory table, then use a nested loop to satisfy joins or - <code>IN</code> clauses. For large subquery results or interestingly nested subqueries, - this is absurdly slow.<ul> -<li>MySQL's query planner can't fold constraints from outer queries into - subqueries.</li> -<li>The generated in-memory table never has any indexes, ever, even when - appropriate indexes are “obvious” from the surrounding query; you cannot - even specify them.</li> -<li>These limitations also affect views, which are evaluated as if they were - subqueries. In combination with the lack of constraint folding in the - planner, this makes filtering or aggregating over large views completely - impractical.</li> -<li>MySQL lacks <a href="http://www.postgresql.org/docs/9.2/static/queries-with.html">common table - expressions</a>. - Even if subquery efficiency problems get fixed, the inability to give - meaningful names to subqueries makes them hard to read and comprehend.</li> -<li>I hope you like <code>CREATE TEMPORARY TABLE AS SELECT</code>, because that's your - only real alternative.</li> -</ul> -</li> -<li><a href="http://en.wikipedia.org/wiki/Select_(SQL)#Window_function">Window - functions</a> do not - exist at all in MySQL. This complicates many kinds of analysis, including - time series analyses and ranking analyses.<ul> -<li>Specific cases (for example, assigning rank numbers to rows) can be - implemented using <a href="http://stackoverflow.com/questions/6473800/assigning-row-rank-numbers">server-side variables and side effects during - <code>SELECT</code></a>. - What? Good luck understanding that code in six months.</li> -</ul> -</li> -<li>Even interesting joins run into trouble. MySQL's query planner has trouble - with a number of cases that can easily arise in well-normalized data:<ul> -<li>Joining and ordering by rows from multiple tables often forces MySQL to - dump the whole join to a temporary table, then sort it -- awful, - especially if you then use <code>LIMIT BY</code> to paginate the results.</li> -<li><code>JOIN</code> clauses with non-trivial conditions, such as joins by range or - joins by similarity, generally cause the planner to revert to table - scans even if the same condition would be indexable outside of a join.</li> -<li>Joins with <code>WHERE</code> clauses that span both tables, where the rows - selected by the <code>WHERE</code> clause are outliers relative to the table - statistics, often cause MySQL to access tables in suboptimal order.</li> -</ul> -</li> -<li>Ok, forget about interesting joins. Even interesting <code>WHERE</code> clauses can run - into trouble: MySQL can't index deterministic functions of a row, either. - While some deterministic functions can be eliminated from the <code>WHERE</code> clause - using simple algebra, many useful cases (whitespace-insensitive comparison, - hash-based comparisons, and so on) can't.<ul> -<li>You can fake these by storing the computed value in the row alongside - the “real” value. This leaves your schema with some ugly data repetition - and a chance for the two to fall out of sync, and clients must use the - “computed” column explicitly.</li> -<li>Oh, and they must maintain the “computed” version explicitly.</li> -<li>Or you can use triggers. Ha. See above.</li> -</ul> -</li> -</ul> -<p>And now you know why MySQL advocates are such big fans of doing data -<em>processing</em> in “the client” or “the app.”</p> -<h3 id="alternate-representations-and-derived-tables">Alternate Representations and Derived Tables</h3> -<p>Many databases let schema designers and administrators abstract the underlying -“physical” table structure from the presentation given to clients, or to some -specific clients, for any of a number of reasons. MySQL tries to let you do -this, too! And fumbles it quite badly.</p> -<ul> -<li>As mentioned above, non-trivial views are basically useless. Queries like - <code>SELECT some columns FROM a_view WHERE id = 53</code> are evaluated in the - stupidest -- and slowest -- possible way. Good luck hiding unusual - partitioning arrangements or a permissions check in a view if you want any - kind of performance.</li> -<li>The poor interactions between triggers and binary logging's default - configuration make it impractical to use triggers to maintain “materialized” - views to avoid the problems with “real” views.<ul> -<li>It also effectively means triggers can't be used to emulate <code>CHECK</code> - constraints and other consistency features.</li> -<li>Code to maintain materialized views is also finicky and hard to get - “right,” especially if the view includes aggregates or interesting joins - over its source data. I hope you enjoy debugging MySQL's procedural - SQL…</li> -</ul> -</li> -<li>For the relatively common case of wanting to abstract partitioned storage - away for clients, MySQL actually has <a href="http://dev.mysql.com/doc/refman/5.5/en/partitioning.html">a - tool</a> for it! But - it comes with <a href="http://dev.mysql.com/doc/refman/5.5/en/partitioning-limitations.html">enough caveats to strangle a - horse</a>:<ul> -<li>It's a separate table engine wrapping a “real” storage engine, which - means it has its own, separate support for engine-specific features: - transactions, foreign keys, and index types, <code>AUTO_INCREMENT</code>, and - others. The syntax for configuring partitions makes selecting the wrong - underlying engine entirely too easy, too.</li> -<li>Partitioned tables may not be the referrent of foreign keys: you can't - have both enforced relationships and this kind of storage management.</li> -<li>MySQL doesn't actually know how to store partitions on separate disks or - filesystems. You still need to reach underneath of MySQL do to actual - storage management.<ul> -<li>Partitioning an InnoDB table under the default InnoDB configuration - stores all of the partitions in the global tablespace file anyways. - Helpful! For per-table configurations, they still all end up - together in the same file. Partitioning InnoDB tables is a waste of - time for managing storage.</li> -</ul> -</li> -<li>TL,DR: MySQL's partition support is so finicky and limited that - MySQL-based apps tend to opt for multiple MySQL servers (“sharding”) - instead.</li> -</ul> -</li> -</ul> -<h3 id="hosting-logic-in-the-database">Hosting Logic In The Database</h3> -<p>Yeah, yeah, the usual reaction to stored procedures and in-DB code is “eww, -yuck!” for some not-terrible reasons, but hear me out on two points:</p> -<ul> -<li>Under the freestanding-database-server paradigm, there will usually be - network latency between database clients and the database itself. There are - two ways to minimize the impact of that: move the data to the code in bulk - to minimize round-trips, or move the code to the data.</li> -<li>Some database administration tasks are better implemented using in-database - code than as freestanding clients: complex data migrations that can't be - expressed as freestanding SQL queries, for example.</li> -</ul> -<p>MySQL, as of version -<a href="http://dev.mysql.com/doc/relnotes/mysql/5.0/en/news-5-0-0.html">5.0</a> -(released in 2003 -- remember that date, I'll come back to it), has support -for in-database code via a procedural SQL-like dialect, like many other SQL -databases. This includes server-side procedures (blocks of stored code that -are invoked outside of any other statements and return statement-like -results), functions (blocks of stored code that compute a result, used in any -expression context such as a <code>SELECT</code> list or <code>WHERE</code> clause), and triggers -(blocks of stored code that run whenever a row is created, modified, or -deleted).</p> -<p>Given the examples of -<a href="http://www.postgresql.org/docs/7.3/static/plpgsql.html">other</a> -<a href="http://msdn.microsoft.com/en-US/library/ms189826(v=sql.90).aspx">contemporaneous</a> -<a href="http://docs.oracle.com/cd/B10501_01/appdev.920/a96624/toc.htm">procedural</a> -<a href="http://www.firebirdsql.org/file/documentation/reference_manuals/reference_material/html/langrefupd15-psql.html">languages</a>, -MySQL's procedural dialect -- an implementation of the -<a href="http://en.wikipedia.org/wiki/SQL/PSM">SQL/PSM</a> language -- is quite limited:</p> -<ul> -<li>There is no language construct for looping over a query result. This seems - like a pretty fundamental feature for a database-hosted language, but no.</li> -<li>There is no language construct for looping while a condition holds. This - seems like a pretty fundamental feature for an imperative language designed - any time after about 1975, but no.</li> -<li>There is no language construct for looping over a range.</li> -<li> -<p>There is, in fact, one language construct for looping: the unconditional - loop. All other iteration control is done via conditional <code>LEAVE</code> - statements, as</p> -<pre><code>BEGIN - DECLARE c CURSOR FOR - SELECT foo, bar, baz - FROM some_table - WHERE some_condition; - DECLARE done INT DEFAULT 0; - DECLARE CONTINUE HANDLER FOR NOT FOUND - SET done = 1; - - DECLARE c_foo INTEGER; - DECLARE c_bar INTEGER; - DECLARE c_baz INTEGER; - - OPEN c; - process_some_table: LOOP - FETCH c INTO c_foo, c_bar, c_baz; - IF done THEN - LEAVE process_some_table; - END IF; - - -- do something with c_foo, c_bar, c_baz - END LOOP; -END; -</code></pre> -<p>The original “structured programming” revolution in the 1960s seems to -have passed the MySQL team by.</p> -</li> -<li> -<p>Okay, I lied. There are two looping constructs: there's also the <code>REPEAT ... - UNTIL condition END REPEAT</code> construct, analogous to C's <code>do {} while - (!condition);</code> loop. But you still can't loop over query results, and you - can't run zero iterations of the loop's main body this way.</p> -</li> -<li>There is nothing resembling a modern exception system with automatic scoping - of handlers or declarative exception management. Error handling is entirely - via Visual Basic-style “on condition X, do Y” instructions, which remain in - effect for the rest of the program's execution.<ul> -<li>In the language shipped with MySQL 5.0, there wasn't a way to signal - errors, either: programmers had to resort to stunts like <a href="http://stackoverflow.com/questions/465727/raise-error-within-mysql-function">intentionally - issuing failing - queries</a>, - instead. Later versions of the language addressed this with the - <a href="http://dev.mysql.com/doc/refman/5.5/en/signal.html"><code>SIGNAL</code> - statement</a>: see, - they <em>can</em> learn from better languages, eventually.</li> -</ul> -</li> -<li>You can't escape to some other language, since MySQL doesn't have an - extension mechanism for server-side languages or a good way to call - out-of-process services during queries.</li> -</ul> -<p>The net result is that developing MySQL stored programs is unpleasant, -uncomfortable, and far more error-prone than it could have been.</p> -<h2 id="by-design">Why Is MySQL The Way It Is?</h2> -<p>MySQL's technology and history contain the seeds of all of these flaws.</p> -<h3 id="pluggable-storage-engines">Pluggable Storage Engines</h3> -<p>Very early in MySQL's life, the MySQL dev team realized that MyISAM was not -the only way to store data, and opted to support other storage backends within -MySQL. This is basically an alright idea; while I personally prefer storage -systems that focus their effort on making one backend work very well, -supporting multiple backends and letting third-party developers write their -own is a pretty good approach too.</p> -<p>Unfortunately, MySQL's storage backend interface puts a very low ceiling on -the ways storage backends can make MySQL behave better.</p> -<p>MySQL's data access paths through table engines are very simple: MySQL asks -the engine to open a table, asks the engine to iterate through the table -returning rows, filters the rows itself (outside of the storage engine), then -asks the engine to close the table. Alternately, MySQL asks the engine to open -a table, asks the engine to retrieve rows in range or for a single value over -a specific index, filters the rows itself, and asks the engine to close the -table.</p> -<p>This simplistic interface frees table engines from having to worry about query -optimization - in theory. Unfortunately, engine-specific features have a large -impact on the performance of various query plans, but the channels back to the -query planner provide very little granularity for estimating cost and prevent -the planner from making good use of the engine in unusual cases. Conversely, -the table engine system is totally isolated from the actual query, and can't -make query-dependent performance choices “on its own.” There's no third path; -the query planner itself is not pluggable.</p> -<p>Similar consequences apply to type checking, support for new types, or even -something as “obvious” as multiple automatic <code>TIMESTAMP</code> columns in the same -table.</p> -<p>Table manipulation -- creation, structural modification, and so on -- runs -into similar problems. MySQL itself parses each <code>CREATE TABLE</code> statement, then -hands off a parsed representation to the table engine so that it can manage -storage. The parsed representation is lossy: there are plenty of forms MySQL's -parser recognizes that aren't representable in a <code>TABLE</code> structure, preventing -engines from implementing, say, column or tuple <code>CHECK</code> constraints without -MySQL's help.</p> -<p>The <a href="http://dev.mysql.com/doc/refman/5.5/en/storage-engines.html">sheer number of table -engines</a> makes -that help very slow in coming. Any change to the table engine interface means -perturbing the code to each engine, making progress on new MySQL-level -features that interact with storage such as better query planning or new SQL -constructs necessarily slow to implement and slow to test.</p> -<h3 id="held-back-by-history">Held Back By History</h3> -<p>The original MySQL team focused on pure read performance and on “ease of use” -(for new users with simple needs, as far as I can tell) over correctness and -completeness, violating Knuth's laws of optimization. Many of these decisions -locked MySQL into behaviours very early in its life that it still displays -now. Features like implicit type conversions legitimately do help streamline -development in very simple cases; experience with <a href="http://me.veekun.com/blog/2012/04/09/php-a-fractal-of-bad-design/">other -languages</a> -unfortunately shows that the same behaviours sandbag development and help hide -bugs in more sophisticated scenarios.</p> -<p>MySQL has since changed hands, and the teams working on MySQL (and MariaDB, -and Percona) are much more mature now than the team that made those early -decisions. MySQL's massive and frequently non-savvy userbase makes it very hard -to introduce breaking changes. At the same time, adding <em>optional</em> breaking -changes via server and client mode flags (such as <code>sql_mode</code>) increases the -cognitive overhead of understanding MySQL's behaviours -- especially when that -behaviour can vary from client to client, or when the server's configuration is -out of the user's control (for example, on a shared host, or on EC2).</p> -<p>A solution similar to Python's <code>from __future__ import</code> pragmas for making -breaking changes opt-in some releases in advance of making them mandatory -might help, but MySQL doesn't have the kind of highly-invested, highly-skilled -user base that would make that effective -- and it still has all of the -problems of modal behaviour.</p> -<h2 id="bad-arguments">Bad Arguments</h2> -<p>Inevitably, someone's going to come along and tell me how wrong I am and how -MySQL is just fine as a database system. These people are everywhere, and they -mean well too, and they are almost all wrong. There are two good reasons to -use MySQL:</p> -<ol> -<li><strong>Some earlier group wrote for it, and we haven't finished porting our code - off of MySQL.</strong></li> -<li><strong>We've considered all of these points, and many more, and decided that - <code>___feature_x___</code> that MySQL offers is worth the hassle.</strong></li> -</ol> -<p>Unfortunately, these aren't the reasons people do give, generally. The -following are much more common:</p> -<ul> -<li><strong>It's good enough.</strong> No it ain't. There are plenty of other equally-capable - data storage systems that don't come with MySQL's huge raft of edge cases - and quirks.<ul> -<li><strong>We haven't run into these problems.</strong> Actually, a lot of these - problems happen <em>silently</em>. Odds are, unless you write your queries and - schema statements with the manual open and refer back to it constantly, - or have been using MySQL since the 3.x era <em>daily</em>, at least some of - these issues have bitten you. The ones that prevent you from using your - database intelligently are very hard to notice in action.</li> -</ul> -</li> -<li><strong>We already know how to use it.</strong> MySQL development and administration - causes brain damage, folks, the same way PHP does. Where PHP teaches - programmers that “array” is the only structure you need, MySQL teaches - people that databases are awkward, slow, hard-to-tune monsters that require - constant attention. That doesn't have to be true; there are comfortable, - fast, and easily-tuned systems out there that don't require daily care and - feeding or the love of a specialist.</li> -<li><strong>It's the only thing our host supports.</strong> <a href="http://linode.com/">Get</a> <a href="http://www.heroku.com/">a</a> <a href="http://gandi.net/">better</a> <a href="https://www.engineyard.com">host</a>. It's - not like they're expensive or hard to find.<ul> -<li><strong>We used it because it was there.</strong> Please hire some fucking software - developers and go back to writing elevator pitches and flirting with Y - Combinator.</li> -</ul> -</li> -<li><strong>Everybody knows MySQL. It's easy to hire MySQL folks.</strong> It's easy to hire - MCSEs, too, but you should be hiring for attitude and ability to learn, not - for specific skillsets, if you want to run a successful software project.<ul> -<li><strong>It's popular.</strong> Sure, and nobody ever got fired for buying - IBM/Microsoft/Adobe. Popularity isn't any indication of quality, and if - we let popularity dictate what technology we use and improve we'll never - get anywhere. Marketing software to geeks is <em>easy</em> - it's just that - lots of high-quality projects don't bother.</li> -</ul> -</li> -<li><strong>It's lightweight.</strong> So's <a href="http://www.sqlite.org">SQLite 3</a> or - <a href="http://www.h2database.com/html/main.html">H2</a>. If you care about deployment - footprint more than any other factor, MySQL is actually pretty clunky (and - embedded MySQL has even bigger problems than freestanding MySQL).</li> -<li><strong>It's getting better, so we might as well stay on it.</strong> <a href="http://dev.mysql.com/doc/refman/5.6/en/mysql-nutshell.html">It's - true</a>, if you go - by feature checklists and the manual, MySQL is improving “rapidly.” 5.6 is - due out soon and superficially looks to contain a number of good changes. I - have two problems with this line of reasoning:<ol> -<li>Why wait? Other databases are good <em>now</em>, not <em>eventually</em>.</li> -<li>MySQL has a history of providing the bare minimum to satisfy a feature -checkbox without actually making the feature work well, work consistently, -or work in combination with other features.</li> -</ol> -</li> -</ul> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/mysql/choose-something-else.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/mysql/choose-something-else.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/mysql/index.html b/.html/mysql/index.html deleted file mode 100644 index 6a60e6b..0000000 --- a/.html/mysql/index.html +++ /dev/null @@ -1,90 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /mysql - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">mysql</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /mysql</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="choose-something-else">Do Not Pass This Way Again</a></li> - - <li><a href="broken-xa">MySQL's Two-Phase Commit Implementation Is Broken</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/mysql">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/packaging-ideas.html b/.html/packaging-ideas.html deleted file mode 100644 index cbf5fe1..0000000 --- a/.html/packaging-ideas.html +++ /dev/null @@ -1,99 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Why “Web 2.0” Matters - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="./">index</a> - - </li> - - <li class="crumb-1 last"> - - packaging-ideas - - </li> - - </ol> - - - - <div id="article"> - <h1 id="why-web-20-matters">Why “Web 2.0” Matters</h1> -<p>It's not about Web 2.0. It's about every stupid industry buzzword that's ever -made programmers roll their eyes.</p> -<h2 id="packaging-ideas">Packaging ideas</h2> -<p>“Web 2.0” gives people who don't live and breathe technology a handy hook to -group ideas on.</p> -<ul> -<li>New, unfamiliar ideas</li> -<li>Ideas people already have but haven't articulated.</li> -</ul> -<h2 id="unpackaging-ideas">Unpackaging ideas</h2> -<p>A well-packaged idea has to do two things:</p> -<ol> -<li>Get the idea into someone's head.</li> -<li>Let someone “unpackage” the idea in their own context and think new things - about it.</li> -</ol> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/packaging-ideas.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/packaging-ideas.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/people/_list.html b/.html/people/_list.html deleted file mode 100644 index 0d71356..0000000 --- a/.html/people/_list.html +++ /dev/null @@ -1,92 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /people - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">people</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /people</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="public-compensation">Notes Towards A Public Compensation Database</a></li> - - <li><a href="rincewind">On Rincewind</a></li> - - <li><a href="rape-culture-and-men">This Is Rape Culture</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/people">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/people/index.html b/.html/people/index.html deleted file mode 100644 index 0d71356..0000000 --- a/.html/people/index.html +++ /dev/null @@ -1,92 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /people - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">people</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /people</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="public-compensation">Notes Towards A Public Compensation Database</a></li> - - <li><a href="rincewind">On Rincewind</a></li> - - <li><a href="rape-culture-and-men">This Is Rape Culture</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/people">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/people/public-compensation.html b/.html/people/public-compensation.html deleted file mode 100644 index 0b0962e..0000000 --- a/.html/people/public-compensation.html +++ /dev/null @@ -1,190 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Notes Towards A Public Compensation Database - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">people</a> - - </li> - - <li class="crumb-2 last"> - - public-compensation - - </li> - - </ol> - - - - <div id="article"> - <h1 id="notes-towards-a-public-compensation-database">Notes Towards A Public Compensation Database</h1> -<p>There's a large body of evidence that silence about compensation is not in the interest of those being paid. -Let's do something about that: let's build a system for analyzing and reporting over salary info.</p> -<h2 id="design-goals">Design Goals</h2> -<ol> -<li> -<p>Respect the safety and consent of the participants.</p> -</li> -<li> -<p>Promote a long-term, public conversation about compensation and salary, both in tech and in other fields.</p> -</li> -</ol> -<h2 id="concerns">Concerns</h2> -<ul> -<li> -<p>Compensation data is historically contentious. - For a cautionary tale, see <a href="https://storify.com/_danilo/ericajoy-s-salary-transparency-experiment-at-googl">@EricaJoy's Storify</a> about salary transparency at Google. - Protecting participants from reprisal requires both effective transparency about how data will be collected and used and a deep, pervasive respect for consent.</p> -</li> -<li> -<p>Naive implementations of anonymity will encourage abusive submissions: defamatory posts, fictional people, attempts to skew the data in a variety of ways. - If this tool succeeds, abuses will discredit it and may damage the larger conversation. - Abuses may also prevent the tool from succeeding.</p> -</li> -<li> -<p><em>Actual laws</em> around salary discussion are not uniform. - Tools should not make it easy for people to harm themselves by mistake.</p> -</li> -<li> -<p>Voluntary disclosure is an inherently unequal process.</p> -</li> -</ul> -<h2 id="design">Design</h2> -<p>The tool stores <em>observations</em> of compensation as of a given date, consisting of one or more of the following compensation types:</p> -<ul> -<li>Salary</li> -<li>Hourly wage</li> -<li>Bonus packages</li> -<li>Equity (at approximate or negotiated value, eg. stock options or grants)</li> -<li>“Other Compensation” of Yearly, Quarterly, Monthly, or One-Time periodicity</li> -</ul> -<p>From these, the tool will derive a “total compensation” for the observation, used as a basis for reporting.</p> -<p>Each observation can carry <em>zero or more</em> structured labels:</p> -<ul> -<li>Employer<ul> -<li>Employer's city, district, and country</li> -</ul> -</li> -<li>Employee's name<ul> -<li>Employee's city, district, and country</li> -</ul> -</li> -<li>Job Title</li> -<li>Years In Role (senority)</li> -<li>Years In Field (experience)</li> -<li>Sex</li> -<li>Gender</li> -<li>Ethnicity</li> -<li>Age</li> -<li>Family Status</li> -<li>Disabilities</li> -</ul> -<p>All labels are <em>strictly</em> voluntary and will be signposted clearly in the submission process. -Every label consists of freeform text or numeric fields. -Text fields will suggest autocompletions using values from existing verified observations, to encourage submitters to enter data consistently.</p> -<p>There are two core workflows:</p> -<ul> -<li>Submitting an observation</li> -<li>Reporting on observed compensation</li> -</ul> -<p>The submission workflow opens a UI which requests a date (defaulting to the date of submission) and a compensation package. -The UI also contains expandable sections to allow the user to choose which labels to add to the submission. -Finally, the UI contains an email address field used to validate the submission. -The validation process will be described later in this document, and serves to both deter abuse and to enable post-facto moderation of a user's submissions.</p> -<p>The report workflow will allow users to select a set of labels and see the distribution of total compensation within those labels, and how it breaks down. -For example, a user may report on compensation for jobs in Toronto, ON, Canada with three years' experience and see the distribution of compensation, and then break that down further by gender and ethnicity.</p> -<p>The report workflow will also users to enter a tentative observation and review how that compares to other compensation packages for similar jobs. -For example, a user may enter a tentative observation for Research In Motion, for Software Team Lead jobs, with a compensation of CAD 80,000/yr, and see the percentile their compensation falls in, and the distribution of compensation observations for the same job.</p> -<h2 id="verification">Verification</h2> -<p>To allow moderation of observations, users must include an email address when submitting observations. -This email address <em>must not be stored</em>, since storing it would allow submissions to be traced to specific people. -Instead, the tool digests the email address with a preconfigured salt, and associates the digest with the unverified observation. -The tool then emails the given address with a verification message, and discards the address.</p> -<p>The verification message contains the following:</p> -<ul> -<li>Prose outlining the verification process.</li> -<li>A brief summary of the observation, containing the date of the observation and the total compensation observed.</li> -<li>A link to the unverified observation, where the user can verify or destroy the observation.</li> -</ul> -<p>The verification system serves three purposes:</p> -<ol> -<li>It discourages people from submitting spurious observations by increasing the time investment needed to get an observation into the data set.</li> -<li>It complicates automated attempts to skew the data.</li> -<li>It allows observations from the same person to be correlated with one another without necessarily identifying the submitter.</li> -</ol> -<p>The correlation provided by the verification system also allows observations to be moderated retroactively: observations shown to be abusive can be used to prevent the author from submitting further observations, and to remove all of that author's submissions (at least, under that address) to be removed from the data set.</p> -<p>Correlations may also allow amending or superceding observations safely. Needs fleshing out.</p> -<h2 id="similar-efforts">Similar Efforts</h2> -<ul> -<li>Piper Miriam's <a href="https://github.com/pipermerriam/am-i-underpaid">Am I Underpaid</a>, which attempts to address the question of compensation equality in a local way.</li> -<li>As mentioned above, <a href="https://storify.com/_danilo/ericajoy-s-salary-transparency-experiment-at-googl">@EricaJoy's Storify</a> covers doing this with Google Docs.</li> -</ul> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/people/public-compensation.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/people/public-compensation.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/people/rape-culture-and-men.html b/.html/people/rape-culture-and-men.html deleted file mode 100644 index 7a66624..0000000 --- a/.html/people/rape-culture-and-men.html +++ /dev/null @@ -1,121 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - This Is Rape Culture - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">people</a> - - </li> - - <li class="crumb-2 last"> - - rape-culture-and-men - - </li> - - </ol> - - - - <div id="article"> - <h1 id="this-is-rape-culture">This Is Rape Culture</h1> -<p>In the last couple of years, I've been interacting with folks who take a more -active hand in gender and social issues, and it's changed the way I see the -word “rape.” It didn't entirely make sense to me how so many people could be -self-identified victims of rape culture while so few people are, even in a -euphemistic way, identifiable as rapists, so I dug a bit at my assumptions.</p> -<p>Growing up immersed in what I now recognize as the early stages of modern -“news” culture, rape was always reported as a violent act. Something so black -and white that if you committed rape, you would know yourself to be a rapist. -Media descriptions of rape and of rapists focussed on acts of overt violence: -“she was in the wrong neighbourhood and got raped at knifepoint,” “held down -and raped,” and so on.</p> -<p>Reading more recent postings on the idea of “rape culture,” however, paints a -very different picture of the same word. “Raped at a party,” “too drunk to -consent,” and other depictions of rape as an act of exploitation (or, -appallingly, convenience or indifference) rather than violence.</p> -<p>Let me be perfectly clear here: without <em>active consent</em>, any sexual contact -is rape or is on the road to it. In that sense, violence, exploitation, -intoxication and other forms of coercion are interchangeable and equally vile.</p> -<p>However, when the public idea of rape is limited to rapes with overt violence, -it's really easy to excuse non-violent coerced sex as “not really rape.” After -all, you didn't hit her, did you? She never said <em>no</em> and <em>meant it</em>, right?</p> -<p>I don't know what I'm going to do with this insight, yet, but I think it's an -important piece towards educating the next generation to be more awesome and -less dangerous to each other and un-learning any bad habits and beliefs I -already have.</p> -<p>Relevant reading:</p> -<ul> -<li><a href="http://captainawkward.com/2012/08/07/322-323-my-friend-group-has-a-case-of-the-creepy-dude-how-do-we-clear-that-up/">“My friend group has a case of Creepy Dude,” by Captain - Awkward</a> - (which also reminded me that it's possible to be a creep to your girlfriend)</li> -<li><a href="http://yesmeansyesblog.wordpress.com/2009/11/12/meet-the-predators/">“Meet the Predators,” from the fantastic Yes Means Yes</a>, cited in the Captain Awkward article but worth a read on its own well-researched merits.</li> -</ul> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/people/rape-culture-and-men.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/people/rape-culture-and-men.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/people/rincewind.html b/.html/people/rincewind.html deleted file mode 100644 index 8c2aca4..0000000 --- a/.html/people/rincewind.html +++ /dev/null @@ -1,114 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - On Rincewind - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">people</a> - - </li> - - <li class="crumb-2 last"> - - rincewind - - </li> - - </ol> - - - - <div id="article"> - <h1 id="on-rincewind">On Rincewind</h1> -<p><a href="http://wiki.lspace.org/mediawiki/index.php/Rincewind">Rincewind</a>, we are -told, is a wizard. On the Disc, wizarding is a profession; Pratchett based -them on the English academic system, with colleges and bursars and tenure. A -wizard is a man of some academic distinction, or a student of such a man; -career wizards are uniformly well-fed, of sound body (if not necessarily of -sound mind) reasonably dressed, opinionated, crankish, and - importantly - -capable of magic.</p> -<p>Rincewind is a wizard: he is not well fed, having spent his life being thrust -from one adventure to the next; his body is more attuned for running away -from things than it is for meandering the halls or sitting by a fire; his -opinions largely revolve around “is this new thing going to eat me,” rather -than more abstract matters; importantly, he is completely incapable of magic, -in spite of years of study.</p> -<p>Rincewind is a wizard, and the interesting thing about that is that the -reader is expected (and I certainly did) take both his and the narrator's -insistence on it at face value. Why shouldn't we?</p> -<hr> -<p>I had a conversation with <a href="https://twitter.com/aeleitch">@aeletich</a> a while -back, while she was teaching herself to program. I don't recall exactly what -prompted it, but at one point I told her to stop worrying about all the -better programmers out there: from everyone else's point of view, she was -already a wizard. There might be better wizards, and worse wizards, but she'd -already passed any sort of bright line delimiting “not a programmer” from -“programmer.”</p> -<p>I think self-identification is important, and overlooked.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/people/rincewind.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/people/rincewind.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/toronto/_list.html b/.html/toronto/_list.html deleted file mode 100644 index 82b9329..0000000 --- a/.html/toronto/_list.html +++ /dev/null @@ -1,88 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /toronto - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">toronto</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /toronto</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="pan-am-carding-lab">Pan-Am Games Civics Lab</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/toronto">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/toronto/index.html b/.html/toronto/index.html deleted file mode 100644 index 82b9329..0000000 --- a/.html/toronto/index.html +++ /dev/null @@ -1,88 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /toronto - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">toronto</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /toronto</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="pan-am-carding-lab">Pan-Am Games Civics Lab</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/toronto">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/toronto/pan-am-carding-lab.html b/.html/toronto/pan-am-carding-lab.html deleted file mode 100644 index e0cc437..0000000 --- a/.html/toronto/pan-am-carding-lab.html +++ /dev/null @@ -1,138 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Pan-Am Games Civics Lab - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">toronto</a> - - </li> - - <li class="crumb-2 last"> - - pan-am-carding-lab - - </li> - - </ol> - - - - <div id="article"> - <h1 id="pan-am-games-civics-lab">Pan-Am Games Civics Lab</h1> -<p>It occurs to me that, with the <a href="http://en.wikipedia.org/wiki/Integrated_Security_Unit">Pan-Am -Games</a> coming up, you -have a prime opportunity to do some hands-on learning about Toronto civics and -policing. (Those of you who did this lab during the G20 summit are excused. If -you are already at risk of police harassment, you are excused. If you've never -been stopped by a cop in your life, this exercise will determine 70% of your -grade.)</p> -<p>Your assignment: do some things that are completely within your rights and -harmless to others.</p> -<ol> -<li> -<p>Dress in lower-middle class drag. Put away the props and costumes of - authority: no suits, no loafers. Jeans, sneakers, t-shirts, jackets are all - in: things chosen as much for their wearability and anonymity as for their - looks. Break them in, if you can; you'll visibly break character if - everything is shop new.</p> -</li> -<li> -<p>Keep quiet. Tell your family where you're going - for safety - but not - social media. If you have an assistant, tell him you're going out, but not - where you're going. Make it as hard as possible for anyone to connect you to - any authority or celebrity your day job gives you.</p> -</li> -<li> -<p>Get a camera. The more visible, the better; you can rent one from Vistek for - a totally achievable number of dollars. Get a strap, too; carrying a camera - by hand is tiring.</p> -</li> -<li> -<p>Go alone.</p> -</li> -<li> -<p>Take a long, slow stroll along the Pan-Am Games' security perimeter.</p> -</li> -</ol> -<p>You will absolutely be stopped by the police Integrated Security Unit, either -through a Toronto officer or an RCMP officer. Remember, you are entirely within -your rights to be there, with a camera, walking. (You'll need the camera to put -yourself on the radar: if you're white, the police will largely ignore you. -Taking pictures is optional, but a lot of fun.)</p> -<p>It's important that you do this <em>without</em> the trappings of authority and -without witnesses. Be powerless. Put yourself at the mercy of the police you -enabled. Experience an unjustified police stop as someone who has no immediate -recourse.</p> -<p>That experience is no fun. It's in turns demeaning, terrifying, embarassing, -and disempowering. <a href="http://www.torontolife.com/informer/features/2015/04/21/skin-im-ive-interrogated-police-50-times-im-black/">For some Torontonians, this is a daily -event</a>.</p> -<p><em>Then</em> come back and talk to me about the Toronto Police Service's <a href="http://www.thestar.com/news/city_hall/2015/04/20/toronto-police-carding-policy-reform-will-require-super-powers-james.html">carding -program</a>.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/toronto/pan-am-carding-lab.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/toronto/pan-am-carding-lab.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file |
