update gnuk documentation
authorNIIBE Yutaka <gniibe@fsij.org>
Thu, 18 Jun 2015 07:23:22 +0000 (16:23 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Thu, 18 Jun 2015 07:23:22 +0000 (16:23 +0900)
41 files changed:
doc-gnuk/_sources/gnome3-gpg-settings.txt
doc-gnuk/_sources/gnuk-keytocard-noremoval.txt
doc-gnuk/_sources/gnuk-keytocard.txt
doc-gnuk/_sources/gpg-settings.txt
doc-gnuk/_static/ajax-loader.gif [new file with mode: 0644]
doc-gnuk/_static/basic.css
doc-gnuk/_static/comment-bright.png [new file with mode: 0644]
doc-gnuk/_static/comment-close.png [new file with mode: 0644]
doc-gnuk/_static/comment.png [new file with mode: 0644]
doc-gnuk/_static/default.css
doc-gnuk/_static/doctools.js
doc-gnuk/_static/down-pressed.png [new file with mode: 0644]
doc-gnuk/_static/down.png [new file with mode: 0644]
doc-gnuk/_static/jquery.js
doc-gnuk/_static/minus.png [new file with mode: 0644]
doc-gnuk/_static/plus.png [new file with mode: 0644]
doc-gnuk/_static/pygments.css
doc-gnuk/_static/searchtools.js
doc-gnuk/_static/sidebar.js [new file with mode: 0644]
doc-gnuk/_static/underscore.js
doc-gnuk/_static/up-pressed.png [new file with mode: 0644]
doc-gnuk/_static/up.png [new file with mode: 0644]
doc-gnuk/_static/websupport.js [new file with mode: 0644]
doc-gnuk/development.html
doc-gnuk/generating-2048-RSA-key.html
doc-gnuk/genindex.html
doc-gnuk/gnome3-gpg-settings.html
doc-gnuk/gnuk-keytocard-noremoval.html
doc-gnuk/gnuk-keytocard.html
doc-gnuk/gnuk-passphrase-setting.html
doc-gnuk/gnuk-personalization.html
doc-gnuk/gnuk-token-initial-configuration.html
doc-gnuk/gpg-settings.html
doc-gnuk/index.html
doc-gnuk/intro.html
doc-gnuk/objects.inv [new file with mode: 0644]
doc-gnuk/search.html
doc-gnuk/searchindex.js [new file with mode: 0644]
doc-gnuk/stop-scdaemon.html
doc-gnuk/udev-rules.html
doc-gnuk/using-gnuk-token-with-another-computer.html

index 2fcf210..5bb6126 100644 (file)
@@ -1,8 +1,8 @@
-==========================
-GnuPG settings for GNOME 3
-==========================
+===========================================
+GnuPG settings for GNOME 3.1x and GNOME 3.0
+===========================================
 
-In the article `GnuPG settings`_, I wrote how I disable GNOME-keyrings for SSH.
+In the section `GnuPG settings`_, I wrote how I disable GNOME-keyrings for SSH.
 
 It was for GNOME 2.  The old days was good, we just disabled GNOME-keyrings
 interference to SSH and customizing our desktop was easy for GNU and UNIX users.
@@ -10,29 +10,33 @@ interference to SSH and customizing our desktop was easy for GNU and UNIX users.
 .. _GnuPG settings: gpg-settings
 
 
-GNOME keyrings in GNOME 3
-=========================
+GNOME keyrings in GNOME 3.1x
+============================
 
-It seems that it is more integrated into the desktop.
-It is difficult to kill it.  It would be possible to kill it simply,
-but then, I can't use, say, wi-fi access (which needs to access "secrets")
-any more.
+In the files /etc/xdg/autostart/gnome-keyring-ssh.desktop
+and /etc/xdg/autostart/gnome-keyring-gpg.desktop,
+we have a line something like: ::
 
-We can't use GNOME configuration tool to disable interference by
-GNOME keyrings any more.  It seems that desktop should not have
-customization these days.
+    OnlyShowIn=GNOME;Unity;MATE;
 
+Please edit this line to: ::
 
-GNOME-SESSION-PROPERTIES
-========================
+    OnlyShowIn=
 
-After struggling some hours, I figured out it is GNOME-SESSION-PROPERTIES
-to disable the interference.  Invoking::
+Then, no desktop environment invokes gnome-keyring for ssh and gpg.  I think that it is The Right Thing.
+
+
+GNOME keyrings in GNOME 3.0 by GNOME-SESSION-PROPERTIES
+=======================================================
+
+We can't use GNOME configuration tool (like GNOME 2) to disable interference by
+GNOME keyrings in GNOME 3.0.
+
+It is GNOME-SESSION-PROPERTIES to disable the interference.  Invoking::
 
  $ gnome-session-properties
 
 and at the tab of "Startup Programs", I removed radio check buttons
 for "GPG Password Agent" and "SSH Key Agent".
 
-
-Now, I use gpg-agent for GnuPG Agent and SSH agent with Gnuk Token.
+Then, I can use proper gpg-agent for GnuPG Agent Service and SSH Agent Service with Gnuk Token in GNOME 3.0.
index ec67452..65704e7 100644 (file)
@@ -5,174 +5,14 @@ Key import from PC to Gnuk Token (no removal)
 This document describes how I put my **keys on PC** to the Token
 without removing keys from PC.
 
-The difference is just not-to-save changes after key imports.
+The difference is only the last step.
+I don't save changes on PC after keytocard.
 
-After personalization, I put my keys into the Token.
+For the steps before the last step, please see `keytocard with removing keys on PC`_.
 
-Here is the log.
+.. _keytocard removing keys: gnuk-keytocard
 
-I invoke GnuPG with my key (4ca7babe) and with ``--homedir`` option
-to specify the directory which contains my secret keys.  ::
-
-  $ gpg --homedir=/home/gniibe/tmp/gnuk-testing-dir --edit-key 4ca7babe 
-  gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc.
-  This is free software: you are free to change and redistribute it.
-  There is NO WARRANTY, to the extent permitted by law.
-  
-  Secret key is available.
-  
-  pub  2048R/4CA7BABE  created: 2010-10-15  expires: never       usage: SC  
-                       trust: ultimate      validity: ultimate
-  sub  2048R/084239CF  created: 2010-10-15  expires: never       usage: E   
-  sub  2048R/5BB065DC  created: 2010-10-22  expires: never       usage: A   
-  [ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
-
-
-Then, GnuPG enters its own command interaction mode.  The prompt is ``gpg>``.
-To enable ``keytocard`` command, I type ``toggle`` command.  ::
-
-  gpg> toggle
-  
-  sec  2048R/4CA7BABE  created: 2010-10-15  expires: never     
-  ssb  2048R/084239CF  created: 2010-10-15  expires: never     
-  ssb  2048R/5BB065DC  created: 2010-10-22  expires: never     
-  (1)  NIIBE Yutaka <gniibe@fsij.org>
-
-Firstly, I import my primary key into Gnuk Token.
-I type ``keytocard`` command, answer ``y`` to confirm keyimport,
-and type ``1`` to say it's signature key. ::
-
-  gpg> keytocard
-  Really move the primary key? (y/N) y
-  Signature key ....: [none]
-  Encryption key....: [none]
-  Authentication key: [none]
-  
-  Please select where to store the key:
-     (1) Signature key
-     (3) Authentication key
-  Your selection? 1
-
-Then, GnuPG asks two passwords.  One is the passphrase of **keys on PC**
-and another is the password of **Gnuk Token**.  Note that the password of
-the token and the password of the keys on PC are different things,
-although they can be same.
-
-Here, I assume that Gnuk Token's admin password of factory setting (12345678).
-
-I enter these passwords. ::
-
-  You need a passphrase to unlock the secret key for
-  user: "NIIBE Yutaka <gniibe@fsij.org>"
-  2048-bit RSA key, ID 4CA7BABE, created 2010-10-15
-  <PASSWORD-KEY-4CA7BABE>
-  gpg: writing new key
-  gpg: 3 Admin PIN attempts remaining before card is permanently locked
-  
-  Please enter the Admin PIN
-  Enter Admin PIN: 12345678
-  
-  sec  2048R/4CA7BABE  created: 2010-10-15  expires: never     
-                       card-no: F517 00000001
-  ssb  2048R/084239CF  created: 2010-10-15  expires: never     
-  ssb  2048R/5BB065DC  created: 2010-10-22  expires: never     
-  (1)  NIIBE Yutaka <gniibe@fsij.org>
-
-The primary key is now on the Token and GnuPG says its card-no (F517 00000001),
-where F517 is the vendor ID of FSIJ.
-
-Secondly, I import my subkey of encryption.  I select key number '1'. ::
-
-  gpg> key 1
-  
-  sec  2048R/4CA7BABE  created: 2010-10-15  expires: never     
-                       card-no: F517 00000001
-  ssb* 2048R/084239CF  created: 2010-10-15  expires: never     
-  ssb  2048R/5BB065DC  created: 2010-10-22  expires: never     
-  (1)  NIIBE Yutaka <gniibe@fsij.org>
-
-You can see that the subkey is marked by '*'.
-I type ``keytocard`` command to import this subkey to Gnuk Token.
-I select ``2`` as it's encryption key. ::
-
-  gpg> keytocard
-  Signature key ....: [none]
-  Encryption key....: [none]
-  Authentication key: [none]
-  
-  Please select where to store the key:
-     (2) Encryption key
-  Your selection? 2
-
-Then, GnuPG asks the passphrase of **keys on PC** again.  I enter. ::
-
-  You need a passphrase to unlock the secret key for
-  user: "NIIBE Yutaka <gniibe@fsij.org>"
-  2048-bit RSA key, ID 084239CF, created 2010-10-15
-  <PASSWORD-KEY-4CA7BABE>
-  gpg: writing new key
-  
-  sec  2048R/4CA7BABE  created: 2010-10-15  expires: never     
-                       card-no: F517 00000001
-  ssb* 2048R/084239CF  created: 2010-10-15  expires: never     
-                       card-no: F517 00000001
-  ssb  2048R/5BB065DC  created: 2010-10-22  expires: never     
-  (1)  NIIBE Yutaka <gniibe@fsij.org>
-
-The sub key is now on the Token and GnuPG says its card-no for it.
-  
-I type ``key 1`` to deselect key number '1'. ::
-
-  gpg> key 1
-  
-  sec  2048R/4CA7BABE  created: 2010-10-15  expires: never     
-                       card-no: F517 00000001
-  ssb  2048R/084239CF  created: 2010-10-15  expires: never     
-                       card-no: F517 00000001
-  ssb  2048R/5BB065DC  created: 2010-10-22  expires: never     
-  (1)  NIIBE Yutaka <gniibe@fsij.org>
-
-Thirdly, I select sub key of authentication which has key number '2'. ::
-
-  gpg> key 2
-  
-  sec  2048R/4CA7BABE  created: 2010-10-15  expires: never     
-                       card-no: F517 00000001
-  ssb  2048R/084239CF  created: 2010-10-15  expires: never     
-                       card-no: F517 00000001
-  ssb* 2048R/5BB065DC  created: 2010-10-22  expires: never     
-  (1)  NIIBE Yutaka <gniibe@fsij.org>
-
-You can see that the subkey number '2' is marked by '*'.
-I type ``keytocard`` command to import this subkey to Gnuk Token.
-I select ``3`` as it's authentication key. ::
-
-  gpg> keytocard
-  Signature key ....: [none]
-  Encryption key....: [none]
-  Authentication key: [none]
-  
-  Please select where to store the key:
-     (3) Authentication key
-  Your selection? 3
-
-Then, GnuPG asks the passphrase of **keys on PC** again.  I enter. ::
-
-  You need a passphrase to unlock the secret key for
-  user: "NIIBE Yutaka <gniibe@fsij.org>"
-  2048-bit RSA key, ID 5BB065DC, created 2010-10-22
-  <PASSWORD-KEY-4CA7BABE>
-  gpg: writing new key
-  
-  sec  2048R/4CA7BABE  created: 2010-10-15  expires: never     
-                       card-no: F517 00000001
-  ssb  2048R/084239CF  created: 2010-10-15  expires: never     
-                       card-no: F517 00000001
-  ssb* 2048R/5BB065DC  created: 2010-10-22  expires: never     
-                       card-no: F517 00000001
-  (1)  NIIBE Yutaka <gniibe@fsij.org>
-
-The sub key is now on the Token and GnuPG says its card-no for it.
+Here is the session log of the last step.
 
 Lastly, I quit GnuPG.  Note that I **don't** save changes. ::
 
index 1e23271..aff8feb 100644 (file)
@@ -22,7 +22,7 @@ See `another document`_ to import keys to the Token from copied directory.
 
 After personalization, I put my keys into the Token.
 
-Here is the log.
+Here is the session log.
 
 I invoke GnuPG with my key (4ca7babe).  ::
 
index 983c92d..57ab153 100644 (file)
@@ -31,7 +31,7 @@ For GnuPG 2.0.x, gpg-agent is always used, so there is no need to specify the ``
 Let gpg-agent manage SSH key
 ============================
 
-I deactivate seahose-agent.  Also, for GNOME 2, I deactivate gnome-keyring managing SSH key. ::
+I deactivate seahorse-agent.  Also, for GNOME 2, I deactivate gnome-keyring managing SSH key. ::
 
   $ gconftool-2 --type bool --set /apps/gnome-keyring/daemon-components/ssh false
 
diff --git a/doc-gnuk/_static/ajax-loader.gif b/doc-gnuk/_static/ajax-loader.gif
new file mode 100644 (file)
index 0000000..61faf8c
Binary files /dev/null and b/doc-gnuk/_static/ajax-loader.gif differ
index 43e8baf..967e36c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Sphinx stylesheet -- basic theme.
  *
- * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
  * :license: BSD, see LICENSE for details.
  *
  */
@@ -89,6 +89,7 @@ div.sphinxsidebar #searchbox input[type="submit"] {
 
 img {
     border: 0;
+    max-width: 100%;
 }
 
 /* -- search page ----------------------------------------------------------- */
@@ -401,10 +402,6 @@ dl.glossary dt {
     margin: 0;
 }
 
-.refcount {
-    color: #060;
-}
-
 .optional {
     font-size: 1.3em;
 }
diff --git a/doc-gnuk/_static/comment-bright.png b/doc-gnuk/_static/comment-bright.png
new file mode 100644 (file)
index 0000000..551517b
Binary files /dev/null and b/doc-gnuk/_static/comment-bright.png differ
diff --git a/doc-gnuk/_static/comment-close.png b/doc-gnuk/_static/comment-close.png
new file mode 100644 (file)
index 0000000..09b54be
Binary files /dev/null and b/doc-gnuk/_static/comment-close.png differ
diff --git a/doc-gnuk/_static/comment.png b/doc-gnuk/_static/comment.png
new file mode 100644 (file)
index 0000000..92feb52
Binary files /dev/null and b/doc-gnuk/_static/comment.png differ
index 21f3f50..5f1399a 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Sphinx stylesheet -- default theme.
  *
- * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
  * :license: BSD, see LICENSE for details.
  *
  */
index d4619fd..c5455c9 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Sphinx JavaScript utilities for all documentation.
  *
- * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
  * :license: BSD, see LICENSE for details.
  *
  */
@@ -32,7 +32,7 @@ if (!window.console || !console.firebug) {
  */
 jQuery.urldecode = function(x) {
   return decodeURIComponent(x).replace(/\+/g, ' ');
-}
+};
 
 /**
  * small helper function to urlencode strings
@@ -61,18 +61,6 @@ jQuery.getQueryParameters = function(s) {
   return result;
 };
 
-/**
- * small function to check if an array contains
- * a given item.
- */
-jQuery.contains = function(arr, item) {
-  for (var i = 0; i < arr.length; i++) {
-    if (arr[i] == item)
-      return true;
-  }
-  return false;
-};
-
 /**
  * highlight a given string on a jquery object by wrapping it in
  * span elements with the given class name.
@@ -180,6 +168,9 @@ var Documentation = {
     var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
     if (terms.length) {
       var body = $('div.body');
+      if (!body.length) {
+        body = $('body');
+      }
       window.setTimeout(function() {
         $.each(terms, function() {
           body.highlightText(this.toLowerCase(), 'highlighted');
diff --git a/doc-gnuk/_static/down-pressed.png b/doc-gnuk/_static/down-pressed.png
new file mode 100644 (file)
index 0000000..6f7ad78
Binary files /dev/null and b/doc-gnuk/_static/down-pressed.png differ
diff --git a/doc-gnuk/_static/down.png b/doc-gnuk/_static/down.png
new file mode 100644 (file)
index 0000000..3003a88
Binary files /dev/null and b/doc-gnuk/_static/down.png differ
index 96d660c..417eb67 100644 (file)
@@ -11,7 +11,7 @@
  * Copyright 2011, The Dojo Foundation
  * Released under the MIT, BSD, and GPL Licenses.
  *
- * Date: Thu Nov 15 18:28:24 BRST 2012
+ * Date: Fri Aug 29 09:46:34 UTC 2014
  */
 (function( window, undefined ) {
 
diff --git a/doc-gnuk/_static/minus.png b/doc-gnuk/_static/minus.png
new file mode 100644 (file)
index 0000000..da1c562
Binary files /dev/null and b/doc-gnuk/_static/minus.png differ
diff --git a/doc-gnuk/_static/plus.png b/doc-gnuk/_static/plus.png
new file mode 100644 (file)
index 0000000..b3cb374
Binary files /dev/null and b/doc-gnuk/_static/plus.png differ
index 1a14f2a..57eadc0 100644 (file)
 .highlight .gr { color: #FF0000 } /* Generic.Error */
 .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
 .highlight .gi { color: #00A000 } /* Generic.Inserted */
-.highlight .go { color: #303030 } /* Generic.Output */
+.highlight .go { color: #333333 } /* Generic.Output */
 .highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
 .highlight .gs { font-weight: bold } /* Generic.Strong */
 .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
-.highlight .gt { color: #0040D0 } /* Generic.Traceback */
+.highlight .gt { color: #0044DD } /* Generic.Traceback */
 .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
 .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
 .highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
@@ -40,6 +40,7 @@
 .highlight .nv { color: #bb60d5 } /* Name.Variable */
 .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
 .highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mb { color: #208050 } /* Literal.Number.Bin */
 .highlight .mf { color: #208050 } /* Literal.Number.Float */
 .highlight .mh { color: #208050 } /* Literal.Number.Hex */
 .highlight .mi { color: #208050 } /* Literal.Number.Integer */
index 663be4c..6e1f06b 100644 (file)
@@ -4,38 +4,11 @@
  *
  * Sphinx JavaScript utilties for the full-text search.
  *
- * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
  * :license: BSD, see LICENSE for details.
  *
  */
 
-/**
- * helper function to return a node containing the
- * search summary for a given text. keywords is a list
- * of stemmed words, hlwords is the list of normal, unstemmed
- * words. the first one is used to find the occurance, the
- * latter for highlighting it.
- */
-
-jQuery.makeSearchSummary = function(text, keywords, hlwords) {
-  var textLower = text.toLowerCase();
-  var start = 0;
-  $.each(keywords, function() {
-    var i = textLower.indexOf(this.toLowerCase());
-    if (i > -1)
-      start = i;
-  });
-  start = Math.max(start - 120, 0);
-  var excerpt = ((start > 0) ? '...' : '') +
-  $.trim(text.substr(start, 240)) +
-  ((start + 240 - text.length) ? '...' : '');
-  var rv = $('<div class="context"></div>').text(excerpt);
-  $.each(hlwords, function() {
-    rv = rv.highlightText(this, 'highlighted');
-  });
-  return rv;
-}
-
 
 /**
  * Porter Stemmer
@@ -220,6 +193,38 @@ var Stemmer = function() {
 }
 
 
+
+/**
+ * Simple result scoring code.
+ */
+var Scorer = {
+  // Implement the following function to further tweak the score for each result
+  // The function takes a result array [filename, title, anchor, descr, score]
+  // and returns the new score.
+  /*
+  score: function(result) {
+    return result[4];
+  },
+  */
+
+  // query matches the full name of an object
+  objNameMatch: 11,
+  // or matches in the last dotted part of the object name
+  objPartialMatch: 6,
+  // Additive scores depending on the priority of the object
+  objPrio: {0:  15,   // used to be importantResults
+            1:  5,   // used to be objectResults
+            2: -5},  // used to be unimportantResults
+  //  Used when the priority is not in the mapping.
+  objPrioDefault: 0,
+
+  // query found in title
+  title: 15,
+  // query found in terms
+  term: 5
+};
+
+
 /**
  * Search Module
  */
@@ -239,8 +244,13 @@ var Search = {
   },
 
   loadIndex : function(url) {
-    $.ajax({type: "GET", url: url, data: null, success: null,
-            dataType: "script", cache: true});
+    $.ajax({type: "GET", url: url, data: null,
+            dataType: "script", cache: true,
+            complete: function(jqxhr, textstatus) {
+              if (textstatus != "success") {
+                document.getElementById("searchindexloader").src = url;
+              }
+            }});
   },
 
   setIndex : function(index) {
@@ -268,19 +278,20 @@ var Search = {
     if (this._pulse_status >= 0)
         return;
     function pulse() {
+      var i;
       Search._pulse_status = (Search._pulse_status + 1) % 4;
       var dotString = '';
-      for (var i = 0; i < Search._pulse_status; i++)
+      for (i = 0; i < Search._pulse_status; i++)
         dotString += '.';
       Search.dots.text(dotString);
       if (Search._pulse_status > -1)
         window.setTimeout(pulse, 500);
-    };
+    }
     pulse();
   },
 
   /**
-   * perform a search for something
+   * perform a search for something (or wait until index is loaded)
    */
   performSearch : function(query) {
     // create the required interface elements
@@ -300,41 +311,46 @@ var Search = {
       this.deferQuery(query);
   },
 
+  /**
+   * execute search (requires search index to be loaded)
+   */
   query : function(query) {
-    var stopwords = ["and","then","into","it","as","are","in","if","for","no","there","their","was","is","be","to","that","but","they","not","such","with","by","a","on","these","of","will","this","near","the","or","at"];
+    var i;
+    var stopwords = ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"];
 
-    // Stem the searchterms and add them to the correct list
+    // stem the searchterms and add them to the correct list
     var stemmer = new Stemmer();
     var searchterms = [];
     var excluded = [];
     var hlterms = [];
     var tmp = query.split(/\s+/);
     var objectterms = [];
-    for (var i = 0; i < tmp.length; i++) {
-      if (tmp[i] != "") {
+    for (i = 0; i < tmp.length; i++) {
+      if (tmp[i] !== "") {
           objectterms.push(tmp[i].toLowerCase());
       }
 
-      if ($u.indexOf(stopwords, tmp[i]) != -1 || tmp[i].match(/^\d+$/) ||
-          tmp[i] == "") {
+      if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i].match(/^\d+$/) ||
+          tmp[i] === "") {
         // skip this "word"
         continue;
       }
       // stem the word
-      var word = stemmer.stemWord(tmp[i]).toLowerCase();
+      var word = stemmer.stemWord(tmp[i].toLowerCase());
+      var toAppend;
       // select the correct list
       if (word[0] == '-') {
-        var toAppend = excluded;
+        toAppend = excluded;
         word = word.substr(1);
       }
       else {
-        var toAppend = searchterms;
+        toAppend = searchterms;
         hlterms.push(tmp[i].toLowerCase());
       }
       // only add if not already in the list
-      if (!$.contains(toAppend, word))
+      if (!$u.contains(toAppend, word))
         toAppend.push(word);
-    };
+    }
     var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
 
     // console.debug('SEARCH: searching for:');
@@ -342,89 +358,51 @@ var Search = {
     // console.info('excluded: ', excluded);
 
     // prepare search
-    var filenames = this._index.filenames;
-    var titles = this._index.titles;
     var terms = this._index.terms;
-    var fileMap = {};
-    var files = null;
-    // different result priorities
-    var importantResults = [];
-    var objectResults = [];
-    var regularResults = [];
-    var unimportantResults = [];
+    var titleterms = this._index.titleterms;
+
+    // array of [filename, title, anchor, descr, score]
+    var results = [];
     $('#search-progress').empty();
 
     // lookup as object
-    for (var i = 0; i < objectterms.length; i++) {
-      var others = [].concat(objectterms.slice(0,i),
-                             objectterms.slice(i+1, objectterms.length))
-      var results = this.performObjectSearch(objectterms[i], others);
-      // Assume first word is most likely to be the object,
-      // other words more likely to be in description.
-      // Therefore put matches for earlier words first.
-      // (Results are eventually used in reverse order).
-      objectResults = results[0].concat(objectResults);
-      importantResults = results[1].concat(importantResults);
-      unimportantResults = results[2].concat(unimportantResults);
+    for (i = 0; i < objectterms.length; i++) {
+      var others = [].concat(objectterms.slice(0, i),
+                             objectterms.slice(i+1, objectterms.length));
+      results = results.concat(this.performObjectSearch(objectterms[i], others));
     }
 
-    // perform the search on the required terms
-    for (var i = 0; i < searchterms.length; i++) {
-      var word = searchterms[i];
-      // no match but word was a required one
-      if ((files = terms[word]) == null)
-        break;
-      if (files.length == undefined) {
-        files = [files];
-      }
-      // create the mapping
-      for (var j = 0; j < files.length; j++) {
-        var file = files[j];
-        if (file in fileMap)
-          fileMap[file].push(word);
-        else
-          fileMap[file] = [word];
-      }
-    }
-
-    // now check if the files don't contain excluded terms
-    for (var file in fileMap) {
-      var valid = true;
-
-      // check if all requirements are matched
-      if (fileMap[file].length != searchterms.length)
-        continue;
-
-      // ensure that none of the excluded terms is in the
-      // search result.
-      for (var i = 0; i < excluded.length; i++) {
-        if (terms[excluded[i]] == file ||
-            $.contains(terms[excluded[i]] || [], file)) {
-          valid = false;
-          break;
-        }
-      }
+    // lookup as search terms in fulltext
+    results = results.concat(this.performTermsSearch(searchterms, excluded, terms, Scorer.term))
+                     .concat(this.performTermsSearch(searchterms, excluded, titleterms, Scorer.title));
 
-      // if we have still a valid result we can add it
-      // to the result list
-      if (valid)
-        regularResults.push([filenames[file], titles[file], '', null]);
+    // let the scorer override scores with a custom scoring function
+    if (Scorer.score) {
+      for (i = 0; i < results.length; i++)
+        results[i][4] = Scorer.score(results[i]);
     }
 
-    // delete unused variables in order to not waste
-    // memory until list is retrieved completely
-    delete filenames, titles, terms;
-
-    // now sort the regular results descending by title
-    regularResults.sort(function(a, b) {
-      var left = a[1].toLowerCase();
-      var right = b[1].toLowerCase();
-      return (left > right) ? -1 : ((left < right) ? 1 : 0);
+    // now sort the results by score (in opposite order of appearance, since the
+    // display function below uses pop() to retrieve items) and then
+    // alphabetically
+    results.sort(function(a, b) {
+      var left = a[4];
+      var right = b[4];
+      if (left > right) {
+        return 1;
+      } else if (left < right) {
+        return -1;
+      } else {
+        // same score: sort alphabetically
+        left = a[1].toLowerCase();
+        right = b[1].toLowerCase();
+        return (left > right) ? -1 : ((left < right) ? 1 : 0);
+      }
     });
 
-    // combine all results
-    var results = unimportantResults.concat(regularResults)
-      .concat(objectResults).concat(importantResults);
+    // for debugging
+    //Search.lastresults = results.slice();  // a copy
+    //console.info('search results:', Search.lastresults);
 
     // print the results
     var resultCount = results.length;
@@ -433,7 +411,7 @@ var Search = {
       if (results.length) {
         var item = results.pop();
         var listItem = $('<li style="display:none"></li>');
-        if (DOCUMENTATION_OPTIONS.FILE_SUFFIX == '') {
+        if (DOCUMENTATION_OPTIONS.FILE_SUFFIX === '') {
           // dirhtml builder
           var dirname = item[0] + '/';
           if (dirname.match(/\/index\/$/)) {
@@ -457,16 +435,18 @@ var Search = {
             displayNextItem();
           });
         } else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
-          $.get(DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' +
-                item[0] + '.txt', function(data) {
-            if (data != '') {
-              listItem.append($.makeSearchSummary(data, searchterms, hlterms));
-              Search.output.append(listItem);
-            }
-            listItem.slideDown(5, function() {
-              displayNextItem();
-            });
-          }, "text");
+          $.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + item[0] + '.txt',
+                  dataType: "text",
+                  complete: function(jqxhr, textstatus) {
+                    var data = jqxhr.responseText;
+                    if (data !== '') {
+                      listItem.append(Search.makeSearchSummary(data, searchterms, hlterms));
+                    }
+                    Search.output.append(listItem);
+                    listItem.slideDown(5, function() {
+                      displayNextItem();
+                    });
+                  }});
         } else {
           // no source available, just display title
           Search.output.append(listItem);
@@ -489,20 +469,32 @@ var Search = {
     displayNextItem();
   },
 
+  /**
+   * search for object names
+   */
   performObjectSearch : function(object, otherterms) {
     var filenames = this._index.filenames;
     var objects = this._index.objects;
     var objnames = this._index.objnames;
     var titles = this._index.titles;
 
-    var importantResults = [];
-    var objectResults = [];
-    var unimportantResults = [];
+    var i;
+    var results = [];
 
     for (var prefix in objects) {
       for (var name in objects[prefix]) {
         var fullname = (prefix ? prefix + '.' : '') + name;
         if (fullname.toLowerCase().indexOf(object) > -1) {
+          var score = 0;
+          var parts = fullname.split('.');
+          // check for different match types: exact matches of full name or
+          // "last name" (i.e. last dotted part)
+          if (fullname == object || parts[parts.length - 1] == object) {
+            score += Scorer.objNameMatch;
+          // matches in last name
+          } else if (parts[parts.length - 1].indexOf(object) > -1) {
+            score += Scorer.objPartialMatch;
+          }
           var match = objects[prefix][name];
           var objname = objnames[match[1]][2];
           var title = titles[match[0]];
@@ -512,7 +504,7 @@ var Search = {
             var haystack = (prefix + ' ' + name + ' ' +
                             objname + ' ' + title).toLowerCase();
             var allfound = true;
-            for (var i = 0; i < otherterms.length; i++) {
+            for (i = 0; i < otherterms.length; i++) {
               if (haystack.indexOf(otherterms[i]) == -1) {
                 allfound = false;
                 break;
@@ -523,37 +515,107 @@ var Search = {
             }
           }
           var descr = objname + _(', in ') + title;
-          anchor = match[3];
-          if (anchor == '')
+
+          var anchor = match[3];
+          if (anchor === '')
             anchor = fullname;
           else if (anchor == '-')
             anchor = objnames[match[1]][1] + '-' + fullname;
-          result = [filenames[match[0]], fullname, '#'+anchor, descr];
-          switch (match[2]) {
-          case 1: objectResults.push(result); break;
-          case 0: importantResults.push(result); break;
-          case 2: unimportantResults.push(result); break;
+          // add custom score for some objects according to scorer
+          if (Scorer.objPrio.hasOwnProperty(match[2])) {
+            score += Scorer.objPrio[match[2]];
+          } else {
+            score += Scorer.objPrioDefault;
           }
+          results.push([filenames[match[0]], fullname, '#'+anchor, descr, score]);
         }
       }
     }
 
-    // sort results descending
-    objectResults.sort(function(a, b) {
-      return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
-    });
+    return results;
+  },
 
-    importantResults.sort(function(a, b) {
-      return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
-    });
+  /**
+   * search for full-text terms in the index
+   */
+  performTermsSearch : function(searchterms, excluded, terms, score) {
+    var filenames = this._index.filenames;
+    var titles = this._index.titles;
 
-    unimportantResults.sort(function(a, b) {
-      return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
-    });
+    var i, j, file, files;
+    var fileMap = {};
+    var results = [];
+
+    // perform the search on the required terms
+    for (i = 0; i < searchterms.length; i++) {
+      var word = searchterms[i];
+      // no match but word was a required one
+      if ((files = terms[word]) === undefined)
+        break;
+      if (files.length === undefined) {
+        files = [files];
+      }
+      // create the mapping
+      for (j = 0; j < files.length; j++) {
+        file = files[j];
+        if (file in fileMap)
+          fileMap[file].push(word);
+        else
+          fileMap[file] = [word];
+      }
+    }
+
+    // now check if the files don't contain excluded terms
+    for (file in fileMap) {
+      var valid = true;
+
+      // check if all requirements are matched
+      if (fileMap[file].length != searchterms.length)
+          continue;
+
+      // ensure that none of the excluded terms is in the search result
+      for (i = 0; i < excluded.length; i++) {
+        if (terms[excluded[i]] == file ||
+          $u.contains(terms[excluded[i]] || [], file)) {
+          valid = false;
+          break;
+        }
+      }
+
+      // if we have still a valid result we can add it to the result list
+      if (valid) {
+        results.push([filenames[file], titles[file], '', null, score]);
+      }
+    }
+    return results;
+  },
 
-    return [importantResults, objectResults, unimportantResults]
+  /**
+   * helper function to return a node containing the
+   * search summary for a given text. keywords is a list
+   * of stemmed words, hlwords is the list of normal, unstemmed
+   * words. the first one is used to find the occurance, the
+   * latter for highlighting it.
+   */
+  makeSearchSummary : function(text, keywords, hlwords) {
+    var textLower = text.toLowerCase();
+    var start = 0;
+    $.each(keywords, function() {
+      var i = textLower.indexOf(this.toLowerCase());
+      if (i > -1)
+        start = i;
+    });
+    start = Math.max(start - 120, 0);
+    var excerpt = ((start > 0) ? '...' : '') +
+      $.trim(text.substr(start, 240)) +
+      ((start + 240 - text.length) ? '...' : '');
+    var rv = $('<div class="context"></div>').text(excerpt);
+    $.each(hlwords, function() {
+      rv = rv.highlightText(this, 'highlighted');
+    });
+    return rv;
   }
-}
+};
 
 $(document).ready(function() {
   Search.init();
diff --git a/doc-gnuk/_static/sidebar.js b/doc-gnuk/_static/sidebar.js
new file mode 100644 (file)
index 0000000..4f09a0d
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * sidebar.js
+ * ~~~~~~~~~~
+ *
+ * This script makes the Sphinx sidebar collapsible.
+ *
+ * .sphinxsidebar contains .sphinxsidebarwrapper.  This script adds
+ * in .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton
+ * used to collapse and expand the sidebar.
+ *
+ * When the sidebar is collapsed the .sphinxsidebarwrapper is hidden
+ * and the width of the sidebar and the margin-left of the document
+ * are decreased. When the sidebar is expanded the opposite happens.
+ * This script saves a per-browser/per-session cookie used to
+ * remember the position of the sidebar among the pages.
+ * Once the browser is closed the cookie is deleted and the position
+ * reset to the default (expanded).
+ *
+ * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+$(function() {
+  
+  
+  
+  
+  
+  
+  
+
+  // global elements used by the functions.
+  // the 'sidebarbutton' element is defined as global after its
+  // creation, in the add_sidebar_button function
+  var bodywrapper = $('.bodywrapper');
+  var sidebar = $('.sphinxsidebar');
+  var sidebarwrapper = $('.sphinxsidebarwrapper');
+
+  // for some reason, the document has no sidebar; do not run into errors
+  if (!sidebar.length) return;
+
+  // original margin-left of the bodywrapper and width of the sidebar
+  // with the sidebar expanded
+  var bw_margin_expanded = bodywrapper.css('margin-left');
+  var ssb_width_expanded = sidebar.width();
+
+  // margin-left of the bodywrapper and width of the sidebar
+  // with the sidebar collapsed
+  var bw_margin_collapsed = '.8em';
+  var ssb_width_collapsed = '.8em';
+
+  // colors used by the current theme
+  var dark_color = $('.related').css('background-color');
+  var light_color = $('.document').css('background-color');
+
+  function sidebar_is_collapsed() {
+    return sidebarwrapper.is(':not(:visible)');
+  }
+
+  function toggle_sidebar() {
+    if (sidebar_is_collapsed())
+      expand_sidebar();
+    else
+      collapse_sidebar();
+  }
+
+  function collapse_sidebar() {
+    sidebarwrapper.hide();
+    sidebar.css('width', ssb_width_collapsed);
+    bodywrapper.css('margin-left', bw_margin_collapsed);
+    sidebarbutton.css({
+        'margin-left': '0',
+        'height': bodywrapper.height()
+    });
+    sidebarbutton.find('span').text('»');
+    sidebarbutton.attr('title', _('Expand sidebar'));
+    document.cookie = 'sidebar=collapsed';
+  }
+
+  function expand_sidebar() {
+    bodywrapper.css('margin-left', bw_margin_expanded);
+    sidebar.css('width', ssb_width_expanded);
+    sidebarwrapper.show();
+    sidebarbutton.css({
+        'margin-left': ssb_width_expanded-12,
+        'height': bodywrapper.height()
+    });
+    sidebarbutton.find('span').text('«');
+    sidebarbutton.attr('title', _('Collapse sidebar'));
+    document.cookie = 'sidebar=expanded';
+  }
+
+  function add_sidebar_button() {
+    sidebarwrapper.css({
+        'float': 'left',
+        'margin-right': '0',
+        'width': ssb_width_expanded - 28
+    });
+    // create the button
+    sidebar.append(
+        '<div id="sidebarbutton"><span>&laquo;</span></div>'
+    );
+    var sidebarbutton = $('#sidebarbutton');
+    light_color = sidebarbutton.css('background-color');
+    // find the height of the viewport to center the '<<' in the page
+    var viewport_height;
+    if (window.innerHeight)
+         viewport_height = window.innerHeight;
+    else
+         viewport_height = $(window).height();
+    sidebarbutton.find('span').css({
+        'display': 'block',
+        'margin-top': (viewport_height - sidebar.position().top - 20) / 2
+    });
+
+    sidebarbutton.click(toggle_sidebar);
+    sidebarbutton.attr('title', _('Collapse sidebar'));
+    sidebarbutton.css({
+        'color': '#FFFFFF',
+        'border-left': '1px solid ' + dark_color,
+        'font-size': '1.2em',
+        'cursor': 'pointer',
+        'height': bodywrapper.height(),
+        'padding-top': '1px',
+        'margin-left': ssb_width_expanded - 12
+    });
+
+    sidebarbutton.hover(
+      function () {
+          $(this).css('background-color', dark_color);
+      },
+      function () {
+          $(this).css('background-color', light_color);
+      }
+    );
+  }
+
+  function set_position_from_cookie() {
+    if (!document.cookie)
+      return;
+    var items = document.cookie.split(';');
+    for(var k=0; k<items.length; k++) {
+      var key_val = items[k].split('=');
+      var key = key_val[0].replace(/ /, "");  // strip leading spaces
+      if (key == 'sidebar') {
+        var value = key_val[1];
+        if ((value == 'collapsed') && (!sidebar_is_collapsed()))
+          collapse_sidebar();
+        else if ((value == 'expanded') && (sidebar_is_collapsed()))
+          expand_sidebar();
+      }
+    }
+  }
+
+  add_sidebar_button();
+  var sidebarbutton = $('#sidebarbutton');
+  set_position_from_cookie();
+});
\ No newline at end of file
index eaba008..b4f49a0 100644 (file)
-//     Underscore.js 1.1.6
-//     (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.
-//     Underscore is freely distributable under the MIT license.
-//     Portions of Underscore are inspired or borrowed from Prototype,
-//     Oliver Steele's Functional, and John Resig's Micro-Templating.
-//     For all details and documentation:
-//     http://documentcloud.github.com/underscore
+//     Underscore.js 1.7.0
+//     http://underscorejs.org
+//     (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+//     Underscore may be freely distributed under the MIT license.
 
 (function() {
 
   // Baseline setup
   // --------------
 
-  // Establish the root object, `window` in the browser, or `global` on the server.
+  // Establish the root object, `window` in the browser, or `exports` on the server.
   var root = this;
 
   // Save the previous value of the `_` variable.
   var previousUnderscore = root._;
 
-  // Establish the object that gets returned to break out of a loop iteration.
-  var breaker = {};
-
   // Save bytes in the minified (but not gzipped) version:
   var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
 
   // Create quick reference variables for speed access to core prototypes.
-  var slice            = ArrayProto.slice,
-      unshift          = ArrayProto.unshift,
-      toString         = ObjProto.toString,
-      hasOwnProperty   = ObjProto.hasOwnProperty;
+  var
+    push             = ArrayProto.push,
+    slice            = ArrayProto.slice,
+    concat           = ArrayProto.concat,
+    toString         = ObjProto.toString,
+    hasOwnProperty   = ObjProto.hasOwnProperty;
 
   // All **ECMAScript 5** native function implementations that we hope to use
   // are declared here.
   var
-    nativeForEach      = ArrayProto.forEach,
-    nativeMap          = ArrayProto.map,
-    nativeReduce       = ArrayProto.reduce,
-    nativeReduceRight  = ArrayProto.reduceRight,
-    nativeFilter       = ArrayProto.filter,
-    nativeEvery        = ArrayProto.every,
-    nativeSome         = ArrayProto.some,
-    nativeIndexOf      = ArrayProto.indexOf,
-    nativeLastIndexOf  = ArrayProto.lastIndexOf,
     nativeIsArray      = Array.isArray,
     nativeKeys         = Object.keys,
     nativeBind         = FuncProto.bind;
 
   // Create a safe reference to the Underscore object for use below.
-  var _ = function(obj) { return new wrapper(obj); };
-
-  // Export the Underscore object for **CommonJS**, with backwards-compatibility
-  // for the old `require()` API. If we're not in CommonJS, add `_` to the
-  // global object.
-  if (typeof module !== 'undefined' && module.exports) {
-    module.exports = _;
-    _._ = _;
+  var _ = function(obj) {
+    if (obj instanceof _) return obj;
+    if (!(this instanceof _)) return new _(obj);
+    this._wrapped = obj;
+  };
+
+  // Export the Underscore object for **Node.js**, with
+  // backwards-compatibility for the old `require()` API. If we're in
+  // the browser, add `_` as a global object.
+  if (typeof exports !== 'undefined') {
+    if (typeof module !== 'undefined' && module.exports) {
+      exports = module.exports = _;
+    }
+    exports._ = _;
   } else {
     root._ = _;
   }
 
   // Current version.
-  _.VERSION = '1.1.6';
+  _.VERSION = '1.7.0';
+
+  // Internal function that returns an efficient (for current engines) version
+  // of the passed-in callback, to be repeatedly applied in other Underscore
+  // functions.
+  var createCallback = function(func, context, argCount) {
+    if (context === void 0) return func;
+    switch (argCount == null ? 3 : argCount) {
+      case 1: return function(value) {
+        return func.call(context, value);
+      };
+      case 2: return function(value, other) {
+        return func.call(context, value, other);
+      };
+      case 3: return function(value, index, collection) {
+        return func.call(context, value, index, collection);
+      };
+      case 4: return function(accumulator, value, index, collection) {
+        return func.call(context, accumulator, value, index, collection);
+      };
+    }
+    return function() {
+      return func.apply(context, arguments);
+    };
+  };
+
+  // A mostly-internal function to generate callbacks that can be applied
+  // to each element in a collection, returning the desired result — either
+  // identity, an arbitrary callback, a property matcher, or a property accessor.
+  _.iteratee = function(value, context, argCount) {
+    if (value == null) return _.identity;
+    if (_.isFunction(value)) return createCallback(value, context, argCount);
+    if (_.isObject(value)) return _.matches(value);
+    return _.property(value);
+  };
 
   // Collection Functions
   // --------------------
 
   // The cornerstone, an `each` implementation, aka `forEach`.
-  // Handles objects implementing `forEach`, arrays, and raw objects.
-  // Delegates to **ECMAScript 5**'s native `forEach` if available.
-  var each = _.each = _.forEach = function(obj, iterator, context) {
-    if (obj == null) return;
-    if (nativeForEach && obj.forEach === nativeForEach) {
-      obj.forEach(iterator, context);
-    } else if (_.isNumber(obj.length)) {
-      for (var i = 0, l = obj.length; i < l; i++) {
-        if (iterator.call(context, obj[i], i, obj) === breaker) return;
+  // Handles raw objects in addition to array-likes. Treats all
+  // sparse array-likes as if they were dense.
+  _.each = _.forEach = function(obj, iteratee, context) {
+    if (obj == null) return obj;
+    iteratee = createCallback(iteratee, context);
+    var i, length = obj.length;
+    if (length === +length) {
+      for (i = 0; i < length; i++) {
+        iteratee(obj[i], i, obj);
       }
     } else {
-      for (var key in obj) {
-        if (hasOwnProperty.call(obj, key)) {
-          if (iterator.call(context, obj[key], key, obj) === breaker) return;
-        }
+      var keys = _.keys(obj);
+      for (i = 0, length = keys.length; i < length; i++) {
+        iteratee(obj[keys[i]], keys[i], obj);
       }
     }
+    return obj;
   };
 
-  // Return the results of applying the iterator to each element.
-  // Delegates to **ECMAScript 5**'s native `map` if available.
-  _.map = function(obj, iterator, context) {
-    var results = [];
-    if (obj == null) return results;
-    if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
-    each(obj, function(value, index, list) {
-      results[results.length] = iterator.call(context, value, index, list);
-    });
+  // Return the results of applying the iteratee to each element.
+  _.map = _.collect = function(obj, iteratee, context) {
+    if (obj == null) return [];
+    iteratee = _.iteratee(iteratee, context);
+    var keys = obj.length !== +obj.length && _.keys(obj),
+        length = (keys || obj).length,
+        results = Array(length),
+        currentKey;
+    for (var index = 0; index < length; index++) {
+      currentKey = keys ? keys[index] : index;
+      results[index] = iteratee(obj[currentKey], currentKey, obj);
+    }
     return results;
   };
 
+  var reduceError = 'Reduce of empty array with no initial value';
+
   // **Reduce** builds up a single result from a list of values, aka `inject`,
-  // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
-  _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
-    var initial = memo !== void 0;
+  // or `foldl`.
+  _.reduce = _.foldl = _.inject = function(obj, iteratee, memo, context) {
     if (obj == null) obj = [];
-    if (nativeReduce && obj.reduce === nativeReduce) {
-      if (context) iterator = _.bind(iterator, context);
-      return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
-    }
-    each(obj, function(value, index, list) {
-      if (!initial && index === 0) {
-        memo = value;
-        initial = true;
-      } else {
-        memo = iterator.call(context, memo, value, index, list);
-      }
-    });
-    if (!initial) throw new TypeError("Reduce of empty array with no initial value");
+    iteratee = createCallback(iteratee, context, 4);
+    var keys = obj.length !== +obj.length && _.keys(obj),
+        length = (keys || obj).length,
+        index = 0, currentKey;
+    if (arguments.length < 3) {
+      if (!length) throw new TypeError(reduceError);
+      memo = obj[keys ? keys[index++] : index++];
+    }
+    for (; index < length; index++) {
+      currentKey = keys ? keys[index] : index;
+      memo = iteratee(memo, obj[currentKey], currentKey, obj);
+    }
     return memo;
   };
 
   // The right-associative version of reduce, also known as `foldr`.
-  // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
-  _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
+  _.reduceRight = _.foldr = function(obj, iteratee, memo, context) {
     if (obj == null) obj = [];
-    if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
-      if (context) iterator = _.bind(iterator, context);
-      return memo !== void 0 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
+    iteratee = createCallback(iteratee, context, 4);
+    var keys = obj.length !== + obj.length && _.keys(obj),
+        index = (keys || obj).length,
+        currentKey;
+    if (arguments.length < 3) {
+      if (!index) throw new TypeError(reduceError);
+      memo = obj[keys ? keys[--index] : --index];
+    }
+    while (index--) {
+      currentKey = keys ? keys[index] : index;
+      memo = iteratee(memo, obj[currentKey], currentKey, obj);
     }
-    var reversed = (_.isArray(obj) ? obj.slice() : _.toArray(obj)).reverse();
-    return _.reduce(reversed, iterator, memo, context);
+    return memo;
   };
 
   // Return the first value which passes a truth test. Aliased as `detect`.
-  _.find = _.detect = function(obj, iterator, context) {
+  _.find = _.detect = function(obj, predicate, context) {
     var result;
-    any(obj, function(value, index, list) {
-      if (iterator.call(context, value, index, list)) {
+    predicate = _.iteratee(predicate, context);
+    _.some(obj, function(value, index, list) {
+      if (predicate(value, index, list)) {
         result = value;
         return true;
       }
   };
 
   // Return all the elements that pass a truth test.
-  // Delegates to **ECMAScript 5**'s native `filter` if available.
   // Aliased as `select`.
-  _.filter = _.select = function(obj, iterator, context) {
+  _.filter = _.select = function(obj, predicate, context) {
     var results = [];
     if (obj == null) return results;
-    if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
-    each(obj, function(value, index, list) {
-      if (iterator.call(context, value, index, list)) results[results.length] = value;
+    predicate = _.iteratee(predicate, context);
+    _.each(obj, function(value, index, list) {
+      if (predicate(value, index, list)) results.push(value);
     });
     return results;
   };
 
   // Return all the elements for which a truth test fails.
-  _.reject = function(obj, iterator, context) {
-    var results = [];
-    if (obj == null) return results;
-    each(obj, function(value, index, list) {
-      if (!iterator.call(context, value, index, list)) results[results.length] = value;
-    });
-    return results;
+  _.reject = function(obj, predicate, context) {
+    return _.filter(obj, _.negate(_.iteratee(predicate)), context);
   };
 
   // Determine whether all of the elements match a truth test.
-  // Delegates to **ECMAScript 5**'s native `every` if available.
   // Aliased as `all`.
-  _.every = _.all = function(obj, iterator, context) {
-    var result = true;
-    if (obj == null) return result;
-    if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
-    each(obj, function(value, index, list) {
-      if (!(result = result && iterator.call(context, value, index, list))) return breaker;
-    });
-    return result;
+  _.every = _.all = function(obj, predicate, context) {
+    if (obj == null) return true;
+    predicate = _.iteratee(predicate, context);
+    var keys = obj.length !== +obj.length && _.keys(obj),
+        length = (keys || obj).length,
+        index, currentKey;
+    for (index = 0; index < length; index++) {
+      currentKey = keys ? keys[index] : index;
+      if (!predicate(obj[currentKey], currentKey, obj)) return false;
+    }
+    return true;
   };
 
   // Determine if at least one element in the object matches a truth test.
-  // Delegates to **ECMAScript 5**'s native `some` if available.
   // Aliased as `any`.
-  var any = _.some = _.any = function(obj, iterator, context) {
-    iterator || (iterator = _.identity);
-    var result = false;
-    if (obj == null) return result;
-    if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
-    each(obj, function(value, index, list) {
-      if (result = iterator.call(context, value, index, list)) return breaker;
-    });
-    return result;
+  _.some = _.any = function(obj, predicate, context) {
+    if (obj == null) return false;
+    predicate = _.iteratee(predicate, context);
+    var keys = obj.length !== +obj.length && _.keys(obj),
+        length = (keys || obj).length,
+        index, currentKey;
+    for (index = 0; index < length; index++) {
+      currentKey = keys ? keys[index] : index;
+      if (predicate(obj[currentKey], currentKey, obj)) return true;
+    }
+    return false;
   };
 
-  // Determine if a given value is included in the array or object using `===`.
-  // Aliased as `contains`.
-  _.include = _.contains = function(obj, target) {
-    var found = false;
-    if (obj == null) return found;
-    if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
-    any(obj, function(value) {
-      if (found = value === target) return true;
-    });
-    return found;
+  // Determine if the array or object contains a given value (using `===`).
+  // Aliased as `include`.
+  _.contains = _.include = function(obj, target) {
+    if (obj == null) return false;
+    if (obj.length !== +obj.length) obj = _.values(obj);
+    return _.indexOf(obj, target) >= 0;
   };
 
   // Invoke a method (with arguments) on every item in a collection.
   _.invoke = function(obj, method) {
     var args = slice.call(arguments, 2);
+    var isFunc = _.isFunction(method);
     return _.map(obj, function(value) {
-      return (method.call ? method || value : value[method]).apply(value, args);
+      return (isFunc ? method : value[method]).apply(value, args);
     });
   };
 
   // Convenience version of a common use case of `map`: fetching a property.
   _.pluck = function(obj, key) {
-    return _.map(obj, function(value){ return value[key]; });
+    return _.map(obj, _.property(key));
   };
 
-  // Return the maximum element or (element-based computation).
-  _.max = function(obj, iterator, context) {
-    if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
-    var result = {computed : -Infinity};
-    each(obj, function(value, index, list) {
-      var computed = iterator ? iterator.call(context, value, index, list) : value;
-      computed >= result.computed && (result = {value : value, computed : computed});
-    });
-    return result.value;
+  // Convenience version of a common use case of `filter`: selecting only objects
+  // containing specific `key:value` pairs.
+  _.where = function(obj, attrs) {
+    return _.filter(obj, _.matches(attrs));
+  };
+
+  // Convenience version of a common use case of `find`: getting the first object
+  // containing specific `key:value` pairs.
+  _.findWhere = function(obj, attrs) {
+    return _.find(obj, _.matches(attrs));
+  };
+
+  // Return the maximum element (or element-based computation).
+  _.max = function(obj, iteratee, context) {
+    var result = -Infinity, lastComputed = -Infinity,
+        value, computed;
+    if (iteratee == null && obj != null) {
+      obj = obj.length === +obj.length ? obj : _.values(obj);
+      for (var i = 0, length = obj.length; i < length; i++) {
+        value = obj[i];
+        if (value > result) {
+          result = value;
+        }
+      }
+    } else {
+      iteratee = _.iteratee(iteratee, context);
+      _.each(obj, function(value, index, list) {
+        computed = iteratee(value, index, list);
+        if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
+          result = value;
+          lastComputed = computed;
+        }
+      });
+    }
+    return result;
   };
 
   // Return the minimum element (or element-based computation).
-  _.min = function(obj, iterator, context) {
-    if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
-    var result = {computed : Infinity};
-    each(obj, function(value, index, list) {
-      var computed = iterator ? iterator.call(context, value, index, list) : value;
-      computed < result.computed && (result = {value : value, computed : computed});
-    });
-    return result.value;
+  _.min = function(obj, iteratee, context) {
+    var result = Infinity, lastComputed = Infinity,
+        value, computed;
+    if (iteratee == null && obj != null) {
+      obj = obj.length === +obj.length ? obj : _.values(obj);
+      for (var i = 0, length = obj.length; i < length; i++) {
+        value = obj[i];
+        if (value < result) {
+          result = value;
+        }
+      }
+    } else {
+      iteratee = _.iteratee(iteratee, context);
+      _.each(obj, function(value, index, list) {
+        computed = iteratee(value, index, list);
+        if (computed < lastComputed || computed === Infinity && result === Infinity) {
+          result = value;
+          lastComputed = computed;
+        }
+      });
+    }
+    return result;
+  };
+
+  // Shuffle a collection, using the modern version of the
+  // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
+  _.shuffle = function(obj) {
+    var set = obj && obj.length === +obj.length ? obj : _.values(obj);
+    var length = set.length;
+    var shuffled = Array(length);
+    for (var index = 0, rand; index < length; index++) {
+      rand = _.random(0, index);
+      if (rand !== index) shuffled[index] = shuffled[rand];
+      shuffled[rand] = set[index];
+    }
+    return shuffled;
   };
 
-  // Sort the object's values by a criterion produced by an iterator.
-  _.sortBy = function(obj, iterator, context) {
+  // Sample **n** random values from a collection.
+  // If **n** is not specified, returns a single random element.
+  // The internal `guard` argument allows it to work with `map`.
+  _.sample = function(obj, n, guard) {
+    if (n == null || guard) {
+      if (obj.length !== +obj.length) obj = _.values(obj);
+      return obj[_.random(obj.length - 1)];
+    }
+    return _.shuffle(obj).slice(0, Math.max(0, n));
+  };
+
+  // Sort the object's values by a criterion produced by an iteratee.
+  _.sortBy = function(obj, iteratee, context) {
+    iteratee = _.iteratee(iteratee, context);
     return _.pluck(_.map(obj, function(value, index, list) {
       return {
-        value : value,
-        criteria : iterator.call(context, value, index, list)
+        value: value,
+        index: index,
+        criteria: iteratee(value, index, list)
       };
     }).sort(function(left, right) {
-      var a = left.criteria, b = right.criteria;
-      return a < b ? -1 : a > b ? 1 : 0;
+      var a = left.criteria;
+      var b = right.criteria;
+      if (a !== b) {
+        if (a > b || a === void 0) return 1;
+        if (a < b || b === void 0) return -1;
+      }
+      return left.index - right.index;
     }), 'value');
   };
 
-  // Use a comparator function to figure out at what index an object should
-  // be inserted so as to maintain order. Uses binary search.
-  _.sortedIndex = function(array, obj, iterator) {
-    iterator || (iterator = _.identity);
+  // An internal function used for aggregate "group by" operations.
+  var group = function(behavior) {
+    return function(obj, iteratee, context) {
+      var result = {};
+      iteratee = _.iteratee(iteratee, context);
+      _.each(obj, function(value, index) {
+        var key = iteratee(value, index, obj);
+        behavior(result, value, key);
+      });
+      return result;
+    };
+  };
+
+  // Groups the object's values by a criterion. Pass either a string attribute
+  // to group by, or a function that returns the criterion.
+  _.groupBy = group(function(result, value, key) {
+    if (_.has(result, key)) result[key].push(value); else result[key] = [value];
+  });
+
+  // Indexes the object's values by a criterion, similar to `groupBy`, but for
+  // when you know that your index values will be unique.
+  _.indexBy = group(function(result, value, key) {
+    result[key] = value;
+  });
+
+  // Counts instances of an object that group by a certain criterion. Pass
+  // either a string attribute to count by, or a function that returns the
+  // criterion.
+  _.countBy = group(function(result, value, key) {
+    if (_.has(result, key)) result[key]++; else result[key] = 1;
+  });
+
+  // Use a comparator function to figure out the smallest index at which
+  // an object should be inserted so as to maintain order. Uses binary search.
+  _.sortedIndex = function(array, obj, iteratee, context) {
+    iteratee = _.iteratee(iteratee, context, 1);
+    var value = iteratee(obj);
     var low = 0, high = array.length;
     while (low < high) {
-      var mid = (low + high) >> 1;
-      iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
+      var mid = low + high >>> 1;
+      if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
     }
     return low;
   };
 
-  // Safely convert anything iterable into a real, live array.
-  _.toArray = function(iterable) {
-    if (!iterable)                return [];
-    if (iterable.toArray)         return iterable.toArray();
-    if (_.isArray(iterable))      return iterable;
-    if (_.isArguments(iterable))  return slice.call(iterable);
-    return _.values(iterable);
+  // Safely create a real, live array from anything iterable.
+  _.toArray = function(obj) {
+    if (!obj) return [];
+    if (_.isArray(obj)) return slice.call(obj);
+    if (obj.length === +obj.length) return _.map(obj, _.identity);
+    return _.values(obj);
   };
 
   // Return the number of elements in an object.
   _.size = function(obj) {
-    return _.toArray(obj).length;
+    if (obj == null) return 0;
+    return obj.length === +obj.length ? obj.length : _.keys(obj).length;
+  };
+
+  // Split a collection into two arrays: one whose elements all satisfy the given
+  // predicate, and one whose elements all do not satisfy the predicate.
+  _.partition = function(obj, predicate, context) {
+    predicate = _.iteratee(predicate, context);
+    var pass = [], fail = [];
+    _.each(obj, function(value, key, obj) {
+      (predicate(value, key, obj) ? pass : fail).push(value);
+    });
+    return [pass, fail];
   };
 
   // Array Functions
   // ---------------
 
   // Get the first element of an array. Passing **n** will return the first N
-  // values in the array. Aliased as `head`. The **guard** check allows it to work
-  // with `_.map`.
-  _.first = _.head = function(array, n, guard) {
-    return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
-  };
-
-  // Returns everything but the first entry of the array. Aliased as `tail`.
-  // Especially useful on the arguments object. Passing an **index** will return
-  // the rest of the values in the array from that index onward. The **guard**
+  // values in the array. Aliased as `head` and `take`. The **guard** check
+  // allows it to work with `_.map`.
+  _.first = _.head = _.take = function(array, n, guard) {
+    if (array == null) return void 0;
+    if (n == null || guard) return array[0];
+    if (n < 0) return [];
+    return slice.call(array, 0, n);
+  };
+
+  // Returns everything but the last entry of the array. Especially useful on
+  // the arguments object. Passing **n** will return all the values in
+  // the array, excluding the last N. The **guard** check allows it to work with
+  // `_.map`.
+  _.initial = function(array, n, guard) {
+    return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
+  };
+
+  // Get the last element of an array. Passing **n** will return the last N
+  // values in the array. The **guard** check allows it to work with `_.map`.
+  _.last = function(array, n, guard) {
+    if (array == null) return void 0;
+    if (n == null || guard) return array[array.length - 1];
+    return slice.call(array, Math.max(array.length - n, 0));
+  };
+
+  // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
+  // Especially useful on the arguments object. Passing an **n** will return
+  // the rest N values in the array. The **guard**
   // check allows it to work with `_.map`.
-  _.rest = _.tail = function(array, index, guard) {
-    return slice.call(array, (index == null) || guard ? 1 : index);
-  };
-
-  // Get the last element of an array.
-  _.last = function(array) {
-    return array[array.length - 1];
+  _.rest = _.tail = _.drop = function(array, n, guard) {
+    return slice.call(array, n == null || guard ? 1 : n);
   };
 
   // Trim out all falsy values from an array.
   _.compact = function(array) {
-    return _.filter(array, function(value){ return !!value; });
+    return _.filter(array, _.identity);
   };
 
-  // Return a completely flattened version of an array.
-  _.flatten = function(array) {
-    return _.reduce(array, function(memo, value) {
-      if (_.isArray(value)) return memo.concat(_.flatten(value));
-      memo[memo.length] = value;
-      return memo;
-    }, []);
+  // Internal implementation of a recursive `flatten` function.
+  var flatten = function(input, shallow, strict, output) {
+    if (shallow && _.every(input, _.isArray)) {
+      return concat.apply(output, input);
+    }
+    for (var i = 0, length = input.length; i < length; i++) {
+      var value = input[i];
+      if (!_.isArray(value) && !_.isArguments(value)) {
+        if (!strict) output.push(value);
+      } else if (shallow) {
+        push.apply(output, value);
+      } else {
+        flatten(value, shallow, strict, output);
+      }
+    }
+    return output;
+  };
+
+  // Flatten out an array, either recursively (by default), or just one level.
+  _.flatten = function(array, shallow) {
+    return flatten(array, shallow, false, []);
   };
 
   // Return a version of the array that does not contain the specified value(s).
   _.without = function(array) {
-    var values = slice.call(arguments, 1);
-    return _.filter(array, function(value){ return !_.include(values, value); });
+    return _.difference(array, slice.call(arguments, 1));
   };
 
   // Produce a duplicate-free version of the array. If the array has already
   // been sorted, you have the option of using a faster algorithm.
   // Aliased as `unique`.
-  _.uniq = _.unique = function(array, isSorted) {
-    return _.reduce(array, function(memo, el, i) {
-      if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo[memo.length] = el;
-      return memo;
-    }, []);
+  _.uniq = _.unique = function(array, isSorted, iteratee, context) {
+    if (array == null) return [];
+    if (!_.isBoolean(isSorted)) {
+      context = iteratee;
+      iteratee = isSorted;
+      isSorted = false;
+    }
+    if (iteratee != null) iteratee = _.iteratee(iteratee, context);
+    var result = [];
+    var seen = [];
+    for (var i = 0, length = array.length; i < length; i++) {
+      var value = array[i];
+      if (isSorted) {
+        if (!i || seen !== value) result.push(value);
+        seen = value;
+      } else if (iteratee) {
+        var computed = iteratee(value, i, array);
+        if (_.indexOf(seen, computed) < 0) {
+          seen.push(computed);
+          result.push(value);
+        }
+      } else if (_.indexOf(result, value) < 0) {
+        result.push(value);
+      }
+    }
+    return result;
+  };
+
+  // Produce an array that contains the union: each distinct element from all of
+  // the passed-in arrays.
+  _.union = function() {
+    return _.uniq(flatten(arguments, true, true, []));
   };
 
   // Produce an array that contains every item shared between all the
   // passed-in arrays.
-  _.intersect = function(array) {
-    var rest = slice.call(arguments, 1);
-    return _.filter(_.uniq(array), function(item) {
-      return _.every(rest, function(other) {
-        return _.indexOf(other, item) >= 0;
-      });
+  _.intersection = function(array) {
+    if (array == null) return [];
+    var result = [];
+    var argsLength = arguments.length;
+    for (var i = 0, length = array.length; i < length; i++) {
+      var item = array[i];
+      if (_.contains(result, item)) continue;
+      for (var j = 1; j < argsLength; j++) {
+        if (!_.contains(arguments[j], item)) break;
+      }
+      if (j === argsLength) result.push(item);
+    }
+    return result;
+  };
+
+  // Take the difference between one array and a number of other arrays.
+  // Only the elements present in just the first array will remain.
+  _.difference = function(array) {
+    var rest = flatten(slice.call(arguments, 1), true, true, []);
+    return _.filter(array, function(value){
+      return !_.contains(rest, value);
     });
   };
 
   // Zip together multiple lists into a single array -- elements that share
   // an index go together.
-  _.zip = function() {
-    var args = slice.call(arguments);
-    var length = _.max(_.pluck(args, 'length'));
-    var results = new Array(length);
-    for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i);
+  _.zip = function(array) {
+    if (array == null) return [];
+    var length = _.max(arguments, 'length').length;
+    var results = Array(length);
+    for (var i = 0; i < length; i++) {
+      results[i] = _.pluck(arguments, i);
+    }
     return results;
   };
 
-  // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
-  // we need this function. Return the position of the first occurrence of an
-  // item in an array, or -1 if the item is not included in the array.
-  // Delegates to **ECMAScript 5**'s native `indexOf` if available.
+  // Converts lists into objects. Pass either a single array of `[key, value]`
+  // pairs, or two parallel arrays of the same length -- one of keys, and one of
+  // the corresponding values.
+  _.object = function(list, values) {
+    if (list == null) return {};
+    var result = {};
+    for (var i = 0, length = list.length; i < length; i++) {
+      if (values) {
+        result[list[i]] = values[i];
+      } else {
+        result[list[i][0]] = list[i][1];
+      }
+    }
+    return result;
+  };
+
+  // Return the position of the first occurrence of an item in an array,
+  // or -1 if the item is not included in the array.
   // If the array is large and already in sort order, pass `true`
   // for **isSorted** to use binary search.
   _.indexOf = function(array, item, isSorted) {
     if (array == null) return -1;
-    var i, l;
+    var i = 0, length = array.length;
     if (isSorted) {
-      i = _.sortedIndex(array, item);
-      return array[i] === item ? i : -1;
+      if (typeof isSorted == 'number') {
+        i = isSorted < 0 ? Math.max(0, length + isSorted) : isSorted;
+      } else {
+        i = _.sortedIndex(array, item);
+        return array[i] === item ? i : -1;
+      }
     }
-    if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
-    for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
+    for (; i < length; i++) if (array[i] === item) return i;
     return -1;
   };
 
-
-  // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
-  _.lastIndexOf = function(array, item) {
+  _.lastIndexOf = function(array, item, from) {
     if (array == null) return -1;
-    if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
-    var i = array.length;
-    while (i--) if (array[i] === item) return i;
+    var idx = array.length;
+    if (typeof from == 'number') {
+      idx = from < 0 ? idx + from + 1 : Math.min(idx, from + 1);
+    }
+    while (--idx >= 0) if (array[idx] === item) return idx;
     return -1;
   };
 
       stop = start || 0;
       start = 0;
     }
-    step = arguments[2] || 1;
+    step = step || 1;
 
-    var len = Math.max(Math.ceil((stop - start) / step), 0);
-    var idx = 0;
-    var range = new Array(len);
+    var length = Math.max(Math.ceil((stop - start) / step), 0);
+    var range = Array(length);
 
-    while(idx < len) {
-      range[idx++] = start;
-      start += step;
+    for (var idx = 0; idx < length; idx++, start += step) {
+      range[idx] = start;
     }
 
     return range;
   // Function (ahem) Functions
   // ------------------
 
+  // Reusable constructor function for prototype setting.
+  var Ctor = function(){};
+
   // Create a function bound to a given object (assigning `this`, and arguments,
-  // optionally). Binding with arguments is also known as `curry`.
-  // Delegates to **ECMAScript 5**'s native `Function.bind` if available.
-  // We check for `func.bind` first, to fail fast when `func` is undefined.
-  _.bind = function(func, obj) {
-    if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
-    var args = slice.call(arguments, 2);
+  // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
+  // available.
+  _.bind = function(func, context) {
+    var args, bound;
+    if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
+    if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
+    args = slice.call(arguments, 2);
+    bound = function() {
+      if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
+      Ctor.prototype = func.prototype;
+      var self = new Ctor;
+      Ctor.prototype = null;
+      var result = func.apply(self, args.concat(slice.call(arguments)));
+      if (_.isObject(result)) return result;
+      return self;
+    };
+    return bound;
+  };
+
+  // Partially apply a function by creating a version that has had some of its
+  // arguments pre-filled, without changing its dynamic `this` context. _ acts
+  // as a placeholder, allowing any combination of arguments to be pre-filled.
+  _.partial = function(func) {
+    var boundArgs = slice.call(arguments, 1);
     return function() {
-      return func.apply(obj, args.concat(slice.call(arguments)));
+      var position = 0;
+      var args = boundArgs.slice();
+      for (var i = 0, length = args.length; i < length; i++) {
+        if (args[i] === _) args[i] = arguments[position++];
+      }
+      while (position < arguments.length) args.push(arguments[position++]);
+      return func.apply(this, args);
     };
   };
 
-  // Bind all of an object's methods to that object. Useful for ensuring that
-  // all callbacks defined on an object belong to it.
+  // Bind a number of an object's methods to that object. Remaining arguments
+  // are the method names to be bound. Useful for ensuring that all callbacks
+  // defined on an object belong to it.
   _.bindAll = function(obj) {
-    var funcs = slice.call(arguments, 1);
-    if (funcs.length == 0) funcs = _.functions(obj);
-    each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
+    var i, length = arguments.length, key;
+    if (length <= 1) throw new Error('bindAll must be passed function names');
+    for (i = 1; i < length; i++) {
+      key = arguments[i];
+      obj[key] = _.bind(obj[key], obj);
+    }
     return obj;
   };
 
   // Memoize an expensive function by storing its results.
   _.memoize = function(func, hasher) {
-    var memo = {};
-    hasher || (hasher = _.identity);
-    return function() {
-      var key = hasher.apply(this, arguments);
-      return hasOwnProperty.call(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
+    var memoize = function(key) {
+      var cache = memoize.cache;
+      var address = hasher ? hasher.apply(this, arguments) : key;
+      if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
+      return cache[address];
     };
+    memoize.cache = {};
+    return memoize;
   };
 
   // Delays a function for the given number of milliseconds, and then calls
   // it with the arguments supplied.
   _.delay = function(func, wait) {
     var args = slice.call(arguments, 2);
-    return setTimeout(function(){ return func.apply(func, args); }, wait);
+    return setTimeout(function(){
+      return func.apply(null, args);
+    }, wait);
   };
 
   // Defers a function, scheduling it to run after the current call stack has
     return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
   };
 
-  // Internal function used to implement `_.throttle` and `_.debounce`.
-  var limit = function(func, wait, debounce) {
-    var timeout;
+  // Returns a function, that, when invoked, will only be triggered at most once
+  // during a given window of time. Normally, the throttled function will run
+  // as much as it can, without ever going more than once per `wait` duration;
+  // but if you'd like to disable the execution on the leading edge, pass
+  // `{leading: false}`. To disable execution on the trailing edge, ditto.
+  _.throttle = function(func, wait, options) {
+    var context, args, result;
+    var timeout = null;
+    var previous = 0;
+    if (!options) options = {};
+    var later = function() {
+      previous = options.leading === false ? 0 : _.now();
+      timeout = null;
+      result = func.apply(context, args);
+      if (!timeout) context = args = null;
+    };
     return function() {
-      var context = this, args = arguments;
-      var throttler = function() {
+      var now = _.now();
+      if (!previous && options.leading === false) previous = now;
+      var remaining = wait - (now - previous);
+      context = this;
+      args = arguments;
+      if (remaining <= 0 || remaining > wait) {
+        clearTimeout(timeout);
         timeout = null;
-        func.apply(context, args);
-      };
-      if (debounce) clearTimeout(timeout);
-      if (debounce || !timeout) timeout = setTimeout(throttler, wait);
+        previous = now;
+        result = func.apply(context, args);
+        if (!timeout) context = args = null;
+      } else if (!timeout && options.trailing !== false) {
+        timeout = setTimeout(later, remaining);
+      }
+      return result;
     };
   };
 
-  // Returns a function, that, when invoked, will only be triggered at most once
-  // during a given window of time.
-  _.throttle = function(func, wait) {
-    return limit(func, wait, false);
-  };
-
   // Returns a function, that, as long as it continues to be invoked, will not
   // be triggered. The function will be called after it stops being called for
-  // N milliseconds.
-  _.debounce = function(func, wait) {
-    return limit(func, wait, true);
-  };
+  // N milliseconds. If `immediate` is passed, trigger the function on the
+  // leading edge, instead of the trailing.
+  _.debounce = function(func, wait, immediate) {
+    var timeout, args, context, timestamp, result;
+
+    var later = function() {
+      var last = _.now() - timestamp;
+
+      if (last < wait && last > 0) {
+        timeout = setTimeout(later, wait - last);
+      } else {
+        timeout = null;
+        if (!immediate) {
+          result = func.apply(context, args);
+          if (!timeout) context = args = null;
+        }
+      }
+    };
 
-  // Returns a function that will be executed at most one time, no matter how
-  // often you call it. Useful for lazy initialization.
-  _.once = function(func) {
-    var ran = false, memo;
     return function() {
-      if (ran) return memo;
-      ran = true;
-      return memo = func.apply(this, arguments);
+      context = this;
+      args = arguments;
+      timestamp = _.now();
+      var callNow = immediate && !timeout;
+      if (!timeout) timeout = setTimeout(later, wait);
+      if (callNow) {
+        result = func.apply(context, args);
+        context = args = null;
+      }
+
+      return result;
     };
   };
 
   // allowing you to adjust arguments, run code before and after, and
   // conditionally execute the original function.
   _.wrap = function(func, wrapper) {
+    return _.partial(wrapper, func);
+  };
+
+  // Returns a negated version of the passed-in predicate.
+  _.negate = function(predicate) {
     return function() {
-      var args = [func].concat(slice.call(arguments));
-      return wrapper.apply(this, args);
+      return !predicate.apply(this, arguments);
     };
   };
 
   // Returns a function that is the composition of a list of functions, each
   // consuming the return value of the function that follows.
   _.compose = function() {
-    var funcs = slice.call(arguments);
+    var args = arguments;
+    var start = args.length - 1;
     return function() {
-      var args = slice.call(arguments);
-      for (var i=funcs.length-1; i >= 0; i--) {
-        args = [funcs[i].apply(this, args)];
-      }
-      return args[0];
+      var i = start;
+      var result = args[start].apply(this, arguments);
+      while (i--) result = args[i].call(this, result);
+      return result;
     };
   };
 
   // Returns a function that will only be executed after being called N times.
   _.after = function(times, func) {
     return function() {
-      if (--times < 1) { return func.apply(this, arguments); }
+      if (--times < 1) {
+        return func.apply(this, arguments);
+      }
+    };
+  };
+
+  // Returns a function that will only be executed before being called N times.
+  _.before = function(times, func) {
+    var memo;
+    return function() {
+      if (--times > 0) {
+        memo = func.apply(this, arguments);
+      } else {
+        func = null;
+      }
+      return memo;
     };
   };
 
+  // Returns a function that will be executed at most one time, no matter how
+  // often you call it. Useful for lazy initialization.
+  _.once = _.partial(_.before, 2);
 
   // Object Functions
   // ----------------
 
   // Retrieve the names of an object's properties.
   // Delegates to **ECMAScript 5**'s native `Object.keys`
-  _.keys = nativeKeys || function(obj) {
-    if (obj !== Object(obj)) throw new TypeError('Invalid object');
+  _.keys = function(obj) {
+    if (!_.isObject(obj)) return [];
+    if (nativeKeys) return nativeKeys(obj);
     var keys = [];
-    for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key;
+    for (var key in obj) if (_.has(obj, key)) keys.push(key);
     return keys;
   };
 
   // Retrieve the values of an object's properties.
   _.values = function(obj) {
-    return _.map(obj, _.identity);
+    var keys = _.keys(obj);
+    var length = keys.length;
+    var values = Array(length);
+    for (var i = 0; i < length; i++) {
+      values[i] = obj[keys[i]];
+    }
+    return values;
+  };
+
+  // Convert an object into a list of `[key, value]` pairs.
+  _.pairs = function(obj) {
+    var keys = _.keys(obj);
+    var length = keys.length;
+    var pairs = Array(length);
+    for (var i = 0; i < length; i++) {
+      pairs[i] = [keys[i], obj[keys[i]]];
+    }
+    return pairs;
+  };
+
+  // Invert the keys and values of an object. The values must be serializable.
+  _.invert = function(obj) {
+    var result = {};
+    var keys = _.keys(obj);
+    for (var i = 0, length = keys.length; i < length; i++) {
+      result[obj[keys[i]]] = keys[i];
+    }
+    return result;
   };
 
   // Return a sorted list of the function names available on the object.
   // Aliased as `methods`
   _.functions = _.methods = function(obj) {
-    return _.filter(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort();
+    var names = [];
+    for (var key in obj) {
+      if (_.isFunction(obj[key])) names.push(key);
+    }
+    return names.sort();
   };
 
   // Extend a given object with all the properties in passed-in object(s).
   _.extend = function(obj) {
-    each(slice.call(arguments, 1), function(source) {
-      for (var prop in source) {
-        if (source[prop] !== void 0) obj[prop] = source[prop];
+    if (!_.isObject(obj)) return obj;
+    var source, prop;
+    for (var i = 1, length = arguments.length; i < length; i++) {
+      source = arguments[i];
+      for (prop in source) {
+        if (hasOwnProperty.call(source, prop)) {
+            obj[prop] = source[prop];
+        }
       }
-    });
+    }
     return obj;
   };
 
+  // Return a copy of the object only containing the whitelisted properties.
+  _.pick = function(obj, iteratee, context) {
+    var result = {}, key;
+    if (obj == null) return result;
+    if (_.isFunction(iteratee)) {
+      iteratee = createCallback(iteratee, context);
+      for (key in obj) {
+        var value = obj[key];
+        if (iteratee(value, key, obj)) result[key] = value;
+      }
+    } else {
+      var keys = concat.apply([], slice.call(arguments, 1));
+      obj = new Object(obj);
+      for (var i = 0, length = keys.length; i < length; i++) {
+        key = keys[i];
+        if (key in obj) result[key] = obj[key];
+      }
+    }
+    return result;
+  };
+
+   // Return a copy of the object without the blacklisted properties.
+  _.omit = function(obj, iteratee, context) {
+    if (_.isFunction(iteratee)) {
+      iteratee = _.negate(iteratee);
+    } else {
+      var keys = _.map(concat.apply([], slice.call(arguments, 1)), String);
+      iteratee = function(value, key) {
+        return !_.contains(keys, key);
+      };
+    }
+    return _.pick(obj, iteratee, context);
+  };
+
   // Fill in a given object with default properties.
   _.defaults = function(obj) {
-    each(slice.call(arguments, 1), function(source) {
+    if (!_.isObject(obj)) return obj;
+    for (var i = 1, length = arguments.length; i < length; i++) {
+      var source = arguments[i];
       for (var prop in source) {
-        if (obj[prop] == null) obj[prop] = source[prop];
+        if (obj[prop] === void 0) obj[prop] = source[prop];
       }
-    });
+    }
     return obj;
   };
 
   // Create a (shallow-cloned) duplicate of an object.
   _.clone = function(obj) {
+    if (!_.isObject(obj)) return obj;
     return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
   };
 
     return obj;
   };
 
+  // Internal recursive comparison function for `isEqual`.
+  var eq = function(a, b, aStack, bStack) {
+    // Identical objects are equal. `0 === -0`, but they aren't identical.
+    // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
+    if (a === b) return a !== 0 || 1 / a === 1 / b;
+    // A strict comparison is necessary because `null == undefined`.
+    if (a == null || b == null) return a === b;
+    // Unwrap any wrapped objects.
+    if (a instanceof _) a = a._wrapped;
+    if (b instanceof _) b = b._wrapped;
+    // Compare `[[Class]]` names.
+    var className = toString.call(a);
+    if (className !== toString.call(b)) return false;
+    switch (className) {
+      // Strings, numbers, regular expressions, dates, and booleans are compared by value.
+      case '[object RegExp]':
+      // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
+      case '[object String]':
+        // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
+        // equivalent to `new String("5")`.
+        return '' + a === '' + b;
+      case '[object Number]':
+        // `NaN`s are equivalent, but non-reflexive.
+        // Object(NaN) is equivalent to NaN
+        if (+a !== +a) return +b !== +b;
+        // An `egal` comparison is performed for other numeric values.
+        return +a === 0 ? 1 / +a === 1 / b : +a === +b;
+      case '[object Date]':
+      case '[object Boolean]':
+        // Coerce dates and booleans to numeric primitive values. Dates are compared by their
+        // millisecond representations. Note that invalid dates with millisecond representations
+        // of `NaN` are not equivalent.
+        return +a === +b;
+    }
+    if (typeof a != 'object' || typeof b != 'object') return false;
+    // Assume equality for cyclic structures. The algorithm for detecting cyclic
+    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
+    var length = aStack.length;
+    while (length--) {
+      // Linear search. Performance is inversely proportional to the number of
+      // unique nested structures.
+      if (aStack[length] === a) return bStack[length] === b;
+    }
+    // Objects with different constructors are not equivalent, but `Object`s
+    // from different frames are.
+    var aCtor = a.constructor, bCtor = b.constructor;
+    if (
+      aCtor !== bCtor &&
+      // Handle Object.create(x) cases
+      'constructor' in a && 'constructor' in b &&
+      !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
+        _.isFunction(bCtor) && bCtor instanceof bCtor)
+    ) {
+      return false;
+    }
+    // Add the first object to the stack of traversed objects.
+    aStack.push(a);
+    bStack.push(b);
+    var size, result;
+    // Recursively compare objects and arrays.
+    if (className === '[object Array]') {
+      // Compare array lengths to determine if a deep comparison is necessary.
+      size = a.length;
+      result = size === b.length;
+      if (result) {
+        // Deep compare the contents, ignoring non-numeric properties.
+        while (size--) {
+          if (!(result = eq(a[size], b[size], aStack, bStack))) break;
+        }
+      }
+    } else {
+      // Deep compare objects.
+      var keys = _.keys(a), key;
+      size = keys.length;
+      // Ensure that both objects contain the same number of properties before comparing deep equality.
+      result = _.keys(b).length === size;
+      if (result) {
+        while (size--) {
+          // Deep compare each member
+          key = keys[size];
+          if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
+        }
+      }
+    }
+    // Remove the first object from the stack of traversed objects.
+    aStack.pop();
+    bStack.pop();
+    return result;
+  };
+
   // Perform a deep comparison to check if two objects are equal.
   _.isEqual = function(a, b) {
-    // Check object identity.
-    if (a === b) return true;
-    // Different types?
-    var atype = typeof(a), btype = typeof(b);
-    if (atype != btype) return false;
-    // Basic equality test (watch out for coercions).
-    if (a == b) return true;
-    // One is falsy and the other truthy.
-    if ((!a && b) || (a && !b)) return false;
-    // Unwrap any wrapped objects.
-    if (a._chain) a = a._wrapped;
-    if (b._chain) b = b._wrapped;
-    // One of them implements an isEqual()?
-    if (a.isEqual) return a.isEqual(b);
-    // Check dates' integer values.
-    if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();
-    // Both are NaN?
-    if (_.isNaN(a) && _.isNaN(b)) return false;
-    // Compare regular expressions.
-    if (_.isRegExp(a) && _.isRegExp(b))
-      return a.source     === b.source &&
-             a.global     === b.global &&
-             a.ignoreCase === b.ignoreCase &&
-             a.multiline  === b.multiline;
-    // If a is not an object by this point, we can't handle it.
-    if (atype !== 'object') return false;
-    // Check for different array lengths before comparing contents.
-    if (a.length && (a.length !== b.length)) return false;
-    // Nothing else worked, deep compare the contents.
-    var aKeys = _.keys(a), bKeys = _.keys(b);
-    // Different object sizes?
-    if (aKeys.length != bKeys.length) return false;
-    // Recursive comparison of contents.
-    for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false;
-    return true;
+    return eq(a, b, [], []);
   };
 
-  // Is a given array or object empty?
+  // Is a given array, string, or object empty?
+  // An "empty" object has no enumerable own-properties.
   _.isEmpty = function(obj) {
-    if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
-    for (var key in obj) if (hasOwnProperty.call(obj, key)) return false;
+    if (obj == null) return true;
+    if (_.isArray(obj) || _.isString(obj) || _.isArguments(obj)) return obj.length === 0;
+    for (var key in obj) if (_.has(obj, key)) return false;
     return true;
   };
 
   // Is a given value a DOM element?
   _.isElement = function(obj) {
-    return !!(obj && obj.nodeType == 1);
+    return !!(obj && obj.nodeType === 1);
   };
 
   // Is a given value an array?
     return toString.call(obj) === '[object Array]';
   };
 
-  // Is a given variable an arguments object?
-  _.isArguments = function(obj) {
-    return !!(obj && hasOwnProperty.call(obj, 'callee'));
+  // Is a given variable an object?
+  _.isObject = function(obj) {
+    var type = typeof obj;
+    return type === 'function' || type === 'object' && !!obj;
   };
 
-  // Is a given value a function?
-  _.isFunction = function(obj) {
-    return !!(obj && obj.constructor && obj.call && obj.apply);
-  };
+  // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
+  _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
+    _['is' + name] = function(obj) {
+      return toString.call(obj) === '[object ' + name + ']';
+    };
+  });
 
-  // Is a given value a string?
-  _.isString = function(obj) {
-    return !!(obj === '' || (obj && obj.charCodeAt && obj.substr));
-  };
+  // Define a fallback version of the method in browsers (ahem, IE), where
+  // there isn't any inspectable "Arguments" type.
+  if (!_.isArguments(arguments)) {
+    _.isArguments = function(obj) {
+      return _.has(obj, 'callee');
+    };
+  }
 
-  // Is a given value a number?
-  _.isNumber = function(obj) {
-    return !!(obj === 0 || (obj && obj.toExponential && obj.toFixed));
+  // Optimize `isFunction` if appropriate. Work around an IE 11 bug.
+  if (typeof /./ !== 'function') {
+    _.isFunction = function(obj) {
+      return typeof obj == 'function' || false;
+    };
+  }
+
+  // Is a given object a finite number?
+  _.isFinite = function(obj) {
+    return isFinite(obj) && !isNaN(parseFloat(obj));
   };
 
-  // Is the given value `NaN`? `NaN` happens to be the only value in JavaScript
-  // that does not equal itself.
+  // Is the given value `NaN`? (NaN is the only number which does not equal itself).
   _.isNaN = function(obj) {
-    return obj !== obj;
+    return _.isNumber(obj) && obj !== +obj;
   };
 
   // Is a given value a boolean?
   _.isBoolean = function(obj) {
-    return obj === true || obj === false;
-  };
-
-  // Is a given value a date?
-  _.isDate = function(obj) {
-    return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear);
-  };
-
-  // Is the given value a regular expression?
-  _.isRegExp = function(obj) {
-    return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false));
+    return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
   };
 
   // Is a given value equal to null?
     return obj === void 0;
   };
 
+  // Shortcut function for checking if an object has a given property directly
+  // on itself (in other words, not on a prototype).
+  _.has = function(obj, key) {
+    return obj != null && hasOwnProperty.call(obj, key);
+  };
+
   // Utility Functions
   // -----------------
 
     return this;
   };
 
-  // Keep the identity function around for default iterators.
+  // Keep the identity function around for default iteratees.
   _.identity = function(value) {
     return value;
   };
 
+  _.constant = function(value) {
+    return function() {
+      return value;
+    };
+  };
+
+  _.noop = function(){};
+
+  _.property = function(key) {
+    return function(obj) {
+      return obj[key];
+    };
+  };
+
+  // Returns a predicate for checking whether an object has a given set of `key:value` pairs.
+  _.matches = function(attrs) {
+    var pairs = _.pairs(attrs), length = pairs.length;
+    return function(obj) {
+      if (obj == null) return !length;
+      obj = new Object(obj);
+      for (var i = 0; i < length; i++) {
+        var pair = pairs[i], key = pair[0];
+        if (pair[1] !== obj[key] || !(key in obj)) return false;
+      }
+      return true;
+    };
+  };
+
   // Run a function **n** times.
-  _.times = function (n, iterator, context) {
-    for (var i = 0; i < n; i++) iterator.call(context, i);
+  _.times = function(n, iteratee, context) {
+    var accum = Array(Math.max(0, n));
+    iteratee = createCallback(iteratee, context, 1);
+    for (var i = 0; i < n; i++) accum[i] = iteratee(i);
+    return accum;
+  };
+
+  // Return a random integer between min and max (inclusive).
+  _.random = function(min, max) {
+    if (max == null) {
+      max = min;
+      min = 0;
+    }
+    return min + Math.floor(Math.random() * (max - min + 1));
   };
 
-  // Add your own custom functions to the Underscore object, ensuring that
-  // they're correctly added to the OOP wrapper as well.
-  _.mixin = function(obj) {
-    each(_.functions(obj), function(name){
-      addToWrapper(name, _[name] = obj[name]);
-    });
+  // A (possibly faster) way to get the current timestamp as an integer.
+  _.now = Date.now || function() {
+    return new Date().getTime();
+  };
+
+   // List of HTML entities for escaping.
+  var escapeMap = {
+    '&': '&amp;',
+    '<': '&lt;',
+    '>': '&gt;',
+    '"': '&quot;',
+    "'": '&#x27;',
+    '`': '&#x60;'
+  };
+  var unescapeMap = _.invert(escapeMap);
+
+  // Functions for escaping and unescaping strings to/from HTML interpolation.
+  var createEscaper = function(map) {
+    var escaper = function(match) {
+      return map[match];
+    };
+    // Regexes for identifying a key that needs to be escaped
+    var source = '(?:' + _.keys(map).join('|') + ')';
+    var testRegexp = RegExp(source);
+    var replaceRegexp = RegExp(source, 'g');
+    return function(string) {
+      string = string == null ? '' : '' + string;
+      return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
+    };
+  };
+  _.escape = createEscaper(escapeMap);
+  _.unescape = createEscaper(unescapeMap);
+
+  // If the value of the named `property` is a function then invoke it with the
+  // `object` as context; otherwise, return it.
+  _.result = function(object, property) {
+    if (object == null) return void 0;
+    var value = object[property];
+    return _.isFunction(value) ? object[property]() : value;
   };
 
   // Generate a unique integer id (unique within the entire client session).
   // Useful for temporary DOM ids.
   var idCounter = 0;
   _.uniqueId = function(prefix) {
-    var id = idCounter++;
+    var id = ++idCounter + '';
     return prefix ? prefix + id : id;
   };
 
   // following template settings to use alternative delimiters.
   _.templateSettings = {
     evaluate    : /<%([\s\S]+?)%>/g,
-    interpolate : /<%=([\s\S]+?)%>/g
+    interpolate : /<%=([\s\S]+?)%>/g,
+    escape      : /<%-([\s\S]+?)%>/g
+  };
+
+  // When customizing `templateSettings`, if you don't want to define an
+  // interpolation, evaluation or escaping regex, we need one that is
+  // guaranteed not to match.
+  var noMatch = /(.)^/;
+
+  // Certain characters need to be escaped so that they can be put into a
+  // string literal.
+  var escapes = {
+    "'":      "'",
+    '\\':     '\\',
+    '\r':     'r',
+    '\n':     'n',
+    '\u2028': 'u2028',
+    '\u2029': 'u2029'
+  };
+
+  var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
+
+  var escapeChar = function(match) {
+    return '\\' + escapes[match];
   };
 
   // JavaScript micro-templating, similar to John Resig's implementation.
   // Underscore templating handles arbitrary delimiters, preserves whitespace,
   // and correctly escapes quotes within interpolated code.
-  _.template = function(str, data) {
-    var c  = _.templateSettings;
-    var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
-      'with(obj||{}){__p.push(\'' +
-      str.replace(/\\/g, '\\\\')
-         .replace(/'/g, "\\'")
-         .replace(c.interpolate, function(match, code) {
-           return "'," + code.replace(/\\'/g, "'") + ",'";
-         })
-         .replace(c.evaluate || null, function(match, code) {
-           return "');" + code.replace(/\\'/g, "'")
-                              .replace(/[\r\n\t]/g, ' ') + "__p.push('";
-         })
-         .replace(/\r/g, '\\r')
-         .replace(/\n/g, '\\n')
-         .replace(/\t/g, '\\t')
-         + "');}return __p.join('');";
-    var func = new Function('obj', tmpl);
-    return data ? func(data) : func;
-  };
-
-  // The OOP Wrapper
-  // ---------------
+  // NB: `oldSettings` only exists for backwards compatibility.
+  _.template = function(text, settings, oldSettings) {
+    if (!settings && oldSettings) settings = oldSettings;
+    settings = _.defaults({}, settings, _.templateSettings);
+
+    // Combine delimiters into one regular expression via alternation.
+    var matcher = RegExp([
+      (settings.escape || noMatch).source,
+      (settings.interpolate || noMatch).source,
+      (settings.evaluate || noMatch).source
+    ].join('|') + '|$', 'g');
+
+    // Compile the template source, escaping string literals appropriately.
+    var index = 0;
+    var source = "__p+='";
+    text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
+      source += text.slice(index, offset).replace(escaper, escapeChar);
+      index = offset + match.length;
+
+      if (escape) {
+        source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
+      } else if (interpolate) {
+        source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
+      } else if (evaluate) {
+        source += "';\n" + evaluate + "\n__p+='";
+      }
+
+      // Adobe VMs need the match returned to produce the correct offest.
+      return match;
+    });
+    source += "';\n";
+
+    // If a variable is not specified, place data values in local scope.
+    if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
+
+    source = "var __t,__p='',__j=Array.prototype.join," +
+      "print=function(){__p+=__j.call(arguments,'');};\n" +
+      source + 'return __p;\n';
+
+    try {
+      var render = new Function(settings.variable || 'obj', '_', source);
+    } catch (e) {
+      e.source = source;
+      throw e;
+    }
+
+    var template = function(data) {
+      return render.call(this, data, _);
+    };
 
+    // Provide the compiled source as a convenience for precompilation.
+    var argument = settings.variable || 'obj';
+    template.source = 'function(' + argument + '){\n' + source + '}';
+
+    return template;
+  };
+
+  // Add a "chain" function. Start chaining a wrapped Underscore object.
+  _.chain = function(obj) {
+    var instance = _(obj);
+    instance._chain = true;
+    return instance;
+  };
+
+  // OOP
+  // ---------------
   // If Underscore is called as a function, it returns a wrapped object that
   // can be used OO-style. This wrapper holds altered versions of all the
   // underscore functions. Wrapped objects may be chained.
-  var wrapper = function(obj) { this._wrapped = obj; };
-
-  // Expose `wrapper.prototype` as `_.prototype`
-  _.prototype = wrapper.prototype;
 
   // Helper function to continue chaining intermediate results.
-  var result = function(obj, chain) {
-    return chain ? _(obj).chain() : obj;
+  var result = function(obj) {
+    return this._chain ? _(obj).chain() : obj;
   };
 
-  // A method to easily add functions to the OOP wrapper.
-  var addToWrapper = function(name, func) {
-    wrapper.prototype[name] = function() {
-      var args = slice.call(arguments);
-      unshift.call(args, this._wrapped);
-      return result(func.apply(_, args), this._chain);
-    };
+  // Add your own custom functions to the Underscore object.
+  _.mixin = function(obj) {
+    _.each(_.functions(obj), function(name) {
+      var func = _[name] = obj[name];
+      _.prototype[name] = function() {
+        var args = [this._wrapped];
+        push.apply(args, arguments);
+        return result.call(this, func.apply(_, args));
+      };
+    });
   };
 
   // Add all of the Underscore functions to the wrapper object.
   _.mixin(_);
 
   // Add all mutator Array functions to the wrapper.
-  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
+  _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
     var method = ArrayProto[name];
-    wrapper.prototype[name] = function() {
-      method.apply(this._wrapped, arguments);
-      return result(this._wrapped, this._chain);
+    _.prototype[name] = function() {
+      var obj = this._wrapped;
+      method.apply(obj, arguments);
+      if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
+      return result.call(this, obj);
     };
   });
 
   // Add all accessor Array functions to the wrapper.
-  each(['concat', 'join', 'slice'], function(name) {
+  _.each(['concat', 'join', 'slice'], function(name) {
     var method = ArrayProto[name];
-    wrapper.prototype[name] = function() {
-      return result(method.apply(this._wrapped, arguments), this._chain);
+    _.prototype[name] = function() {
+      return result.call(this, method.apply(this._wrapped, arguments));
     };
   });
 
-  // Start chaining a wrapped Underscore object.
-  wrapper.prototype.chain = function() {
-    this._chain = true;
-    return this;
-  };
-
   // Extracts the result from a wrapped and chained object.
-  wrapper.prototype.value = function() {
+  _.prototype.value = function() {
     return this._wrapped;
   };
 
-})();
+  // AMD registration happens at the end for compatibility with AMD loaders
+  // that may not enforce next-turn semantics on modules. Even though general
+  // practice for AMD registration is to be anonymous, underscore registers
+  // as a named module because, like jQuery, it is a base library that is
+  // popular enough to be bundled in a third party lib, but not be part of
+  // an AMD load request. Those cases could generate an error when an
+  // anonymous define() is called outside of a loader request.
+  if (typeof define === 'function' && define.amd) {
+    define('underscore', [], function() {
+      return _;
+    });
+  }
+}.call(this));
diff --git a/doc-gnuk/_static/up-pressed.png b/doc-gnuk/_static/up-pressed.png
new file mode 100644 (file)
index 0000000..8bd587a
Binary files /dev/null and b/doc-gnuk/_static/up-pressed.png differ
diff --git a/doc-gnuk/_static/up.png b/doc-gnuk/_static/up.png
new file mode 100644 (file)
index 0000000..b946256
Binary files /dev/null and b/doc-gnuk/_static/up.png differ
diff --git a/doc-gnuk/_static/websupport.js b/doc-gnuk/_static/websupport.js
new file mode 100644 (file)
index 0000000..71c0a13
--- /dev/null
@@ -0,0 +1,808 @@
+/*
+ * websupport.js
+ * ~~~~~~~~~~~~~
+ *
+ * sphinx.websupport utilties for all documentation.
+ *
+ * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+(function($) {
+  $.fn.autogrow = function() {
+    return this.each(function() {
+    var textarea = this;
+
+    $.fn.autogrow.resize(textarea);
+
+    $(textarea)
+      .focus(function() {
+        textarea.interval = setInterval(function() {
+          $.fn.autogrow.resize(textarea);
+        }, 500);
+      })
+      .blur(function() {
+        clearInterval(textarea.interval);
+      });
+    });
+  };
+
+  $.fn.autogrow.resize = function(textarea) {
+    var lineHeight = parseInt($(textarea).css('line-height'), 10);
+    var lines = textarea.value.split('\n');
+    var columns = textarea.cols;
+    var lineCount = 0;
+    $.each(lines, function() {
+      lineCount += Math.ceil(this.length / columns) || 1;
+    });
+    var height = lineHeight * (lineCount + 1);
+    $(textarea).css('height', height);
+  };
+})(jQuery);
+
+(function($) {
+  var comp, by;
+
+  function init() {
+    initEvents();
+    initComparator();
+  }
+
+  function initEvents() {
+    $('a.comment-close').live("click", function(event) {
+      event.preventDefault();
+      hide($(this).attr('id').substring(2));
+    });
+    $('a.vote').live("click", function(event) {
+      event.preventDefault();
+      handleVote($(this));
+    });
+    $('a.reply').live("click", function(event) {
+      event.preventDefault();
+      openReply($(this).attr('id').substring(2));
+    });
+    $('a.close-reply').live("click", function(event) {
+      event.preventDefault();
+      closeReply($(this).attr('id').substring(2));
+    });
+    $('a.sort-option').live("click", function(event) {
+      event.preventDefault();
+      handleReSort($(this));
+    });
+    $('a.show-proposal').live("click", function(event) {
+      event.preventDefault();
+      showProposal($(this).attr('id').substring(2));
+    });
+    $('a.hide-proposal').live("click", function(event) {
+      event.preventDefault();
+      hideProposal($(this).attr('id').substring(2));
+    });
+    $('a.show-propose-change').live("click", function(event) {
+      event.preventDefault();
+      showProposeChange($(this).attr('id').substring(2));
+    });
+    $('a.hide-propose-change').live("click", function(event) {
+      event.preventDefault();
+      hideProposeChange($(this).attr('id').substring(2));
+    });
+    $('a.accept-comment').live("click", function(event) {
+      event.preventDefault();
+      acceptComment($(this).attr('id').substring(2));
+    });
+    $('a.delete-comment').live("click", function(event) {
+      event.preventDefault();
+      deleteComment($(this).attr('id').substring(2));
+    });
+    $('a.comment-markup').live("click", function(event) {
+      event.preventDefault();
+      toggleCommentMarkupBox($(this).attr('id').substring(2));
+    });
+  }
+
+  /**
+   * Set comp, which is a comparator function used for sorting and
+   * inserting comments into the list.
+   */
+  function setComparator() {
+    // If the first three letters are "asc", sort in ascending order
+    // and remove the prefix.
+    if (by.substring(0,3) == 'asc') {
+      var i = by.substring(3);
+      comp = function(a, b) { return a[i] - b[i]; };
+    } else {
+      // Otherwise sort in descending order.
+      comp = function(a, b) { return b[by] - a[by]; };
+    }
+
+    // Reset link styles and format the selected sort option.
+    $('a.sel').attr('href', '#').removeClass('sel');
+    $('a.by' + by).removeAttr('href').addClass('sel');
+  }
+
+  /**
+   * Create a comp function. If the user has preferences stored in
+   * the sortBy cookie, use those, otherwise use the default.
+   */
+  function initComparator() {
+    by = 'rating'; // Default to sort by rating.
+    // If the sortBy cookie is set, use that instead.
+    if (document.cookie.length > 0) {
+      var start = document.cookie.indexOf('sortBy=');
+      if (start != -1) {
+        start = start + 7;
+        var end = document.cookie.indexOf(";", start);
+        if (end == -1) {
+          end = document.cookie.length;
+          by = unescape(document.cookie.substring(start, end));
+        }
+      }
+    }
+    setComparator();
+  }
+
+  /**
+   * Show a comment div.
+   */
+  function show(id) {
+    $('#ao' + id).hide();
+    $('#ah' + id).show();
+    var context = $.extend({id: id}, opts);
+    var popup = $(renderTemplate(popupTemplate, context)).hide();
+    popup.find('textarea[name="proposal"]').hide();
+    popup.find('a.by' + by).addClass('sel');
+    var form = popup.find('#cf' + id);
+    form.submit(function(event) {
+      event.preventDefault();
+      addComment(form);
+    });
+    $('#s' + id).after(popup);
+    popup.slideDown('fast', function() {
+      getComments(id);
+    });
+  }
+
+  /**
+   * Hide a comment div.
+   */
+  function hide(id) {
+    $('#ah' + id).hide();
+    $('#ao' + id).show();
+    var div = $('#sc' + id);
+    div.slideUp('fast', function() {
+      div.remove();
+    });
+  }
+
+  /**
+   * Perform an ajax request to get comments for a node
+   * and insert the comments into the comments tree.
+   */
+  function getComments(id) {
+    $.ajax({
+     type: 'GET',
+     url: opts.getCommentsURL,
+     data: {node: id},
+     success: function(data, textStatus, request) {
+       var ul = $('#cl' + id);
+       var speed = 100;
+       $('#cf' + id)
+         .find('textarea[name="proposal"]')
+         .data('source', data.source);
+
+       if (data.comments.length === 0) {
+         ul.html('<li>No comments yet.</li>');
+         ul.data('empty', true);
+       } else {
+         // If there are comments, sort them and put them in the list.
+         var comments = sortComments(data.comments);
+         speed = data.comments.length * 100;
+         appendComments(comments, ul);
+         ul.data('empty', false);
+       }
+       $('#cn' + id).slideUp(speed + 200);
+       ul.slideDown(speed);
+     },
+     error: function(request, textStatus, error) {
+       showError('Oops, there was a problem retrieving the comments.');
+     },
+     dataType: 'json'
+    });
+  }
+
+  /**
+   * Add a comment via ajax and insert the comment into the comment tree.
+   */
+  function addComment(form) {
+    var node_id = form.find('input[name="node"]').val();
+    var parent_id = form.find('input[name="parent"]').val();
+    var text = form.find('textarea[name="comment"]').val();
+    var proposal = form.find('textarea[name="proposal"]').val();
+
+    if (text == '') {
+      showError('Please enter a comment.');
+      return;
+    }
+
+    // Disable the form that is being submitted.
+    form.find('textarea,input').attr('disabled', 'disabled');
+
+    // Send the comment to the server.
+    $.ajax({
+      type: "POST",
+      url: opts.addCommentURL,
+      dataType: 'json',
+      data: {
+        node: node_id,
+        parent: parent_id,
+        text: text,
+        proposal: proposal
+      },
+      success: function(data, textStatus, error) {
+        // Reset the form.
+        if (node_id) {
+          hideProposeChange(node_id);
+        }
+        form.find('textarea')
+          .val('')
+          .add(form.find('input'))
+          .removeAttr('disabled');
+       var ul = $('#cl' + (node_id || parent_id));
+        if (ul.data('empty')) {
+          $(ul).empty();
+          ul.data('empty', false);
+        }
+        insertComment(data.comment);
+        var ao = $('#ao' + node_id);
+        ao.find('img').attr({'src': opts.commentBrightImage});
+        if (node_id) {
+          // if this was a "root" comment, remove the commenting box
+          // (the user can get it back by reopening the comment popup)
+          $('#ca' + node_id).slideUp();
+        }
+      },
+      error: function(request, textStatus, error) {
+        form.find('textarea,input').removeAttr('disabled');
+        showError('Oops, there was a problem adding the comment.');
+      }
+    });
+  }
+
+  /**
+   * Recursively append comments to the main comment list and children
+   * lists, creating the comment tree.
+   */
+  function appendComments(comments, ul) {
+    $.each(comments, function() {
+      var div = createCommentDiv(this);
+      ul.append($(document.createElement('li')).html(div));
+      appendComments(this.children, div.find('ul.comment-children'));
+      // To avoid stagnating data, don't store the comments children in data.
+      this.children = null;
+      div.data('comment', this);
+    });
+  }
+
+  /**
+   * After adding a new comment, it must be inserted in the correct
+   * location in the comment tree.
+   */
+  function insertComment(comment) {
+    var div = createCommentDiv(comment);
+
+    // To avoid stagnating data, don't store the comments children in data.
+    comment.children = null;
+    div.data('comment', comment);
+
+    var ul = $('#cl' + (comment.node || comment.parent));
+    var siblings = getChildren(ul);
+
+    var li = $(document.createElement('li'));
+    li.hide();
+
+    // Determine where in the parents children list to insert this comment.
+    for(i=0; i < siblings.length; i++) {
+      if (comp(comment, siblings[i]) <= 0) {
+        $('#cd' + siblings[i].id)
+          .parent()
+          .before(li.html(div));
+        li.slideDown('fast');
+        return;
+      }
+    }
+
+    // If we get here, this comment rates lower than all the others,
+    // or it is the only comment in the list.
+    ul.append(li.html(div));
+    li.slideDown('fast');
+  }
+
+  function acceptComment(id) {
+    $.ajax({
+      type: 'POST',
+      url: opts.acceptCommentURL,
+      data: {id: id},
+      success: function(data, textStatus, request) {
+        $('#cm' + id).fadeOut('fast');
+        $('#cd' + id).removeClass('moderate');
+      },
+      error: function(request, textStatus, error) {
+        showError('Oops, there was a problem accepting the comment.');
+      }
+    });
+  }
+
+  function deleteComment(id) {
+    $.ajax({
+      type: 'POST',
+      url: opts.deleteCommentURL,
+      data: {id: id},
+      success: function(data, textStatus, request) {
+        var div = $('#cd' + id);
+        if (data == 'delete') {
+          // Moderator mode: remove the comment and all children immediately
+          div.slideUp('fast', function() {
+            div.remove();
+          });
+          return;
+        }
+        // User mode: only mark the comment as deleted
+        div
+          .find('span.user-id:first')
+          .text('[deleted]').end()
+          .find('div.comment-text:first')
+          .text('[deleted]').end()
+          .find('#cm' + id + ', #dc' + id + ', #ac' + id + ', #rc' + id +
+                ', #sp' + id + ', #hp' + id + ', #cr' + id + ', #rl' + id)
+          .remove();
+        var comment = div.data('comment');
+        comment.username = '[deleted]';
+        comment.text = '[deleted]';
+        div.data('comment', comment);
+      },
+      error: function(request, textStatus, error) {
+        showError('Oops, there was a problem deleting the comment.');
+      }
+    });
+  }
+
+  function showProposal(id) {
+    $('#sp' + id).hide();
+    $('#hp' + id).show();
+    $('#pr' + id).slideDown('fast');
+  }
+
+  function hideProposal(id) {
+    $('#hp' + id).hide();
+    $('#sp' + id).show();
+    $('#pr' + id).slideUp('fast');
+  }
+
+  function showProposeChange(id) {
+    $('#pc' + id).hide();
+    $('#hc' + id).show();
+    var textarea = $('#pt' + id);
+    textarea.val(textarea.data('source'));
+    $.fn.autogrow.resize(textarea[0]);
+    textarea.slideDown('fast');
+  }
+
+  function hideProposeChange(id) {
+    $('#hc' + id).hide();
+    $('#pc' + id).show();
+    var textarea = $('#pt' + id);
+    textarea.val('').removeAttr('disabled');
+    textarea.slideUp('fast');
+  }
+
+  function toggleCommentMarkupBox(id) {
+    $('#mb' + id).toggle();
+  }
+
+  /** Handle when the user clicks on a sort by link. */
+  function handleReSort(link) {
+    var classes = link.attr('class').split(/\s+/);
+    for (var i=0; i<classes.length; i++) {
+      if (classes[i] != 'sort-option') {
+       by = classes[i].substring(2);
+      }
+    }
+    setComparator();
+    // Save/update the sortBy cookie.
+    var expiration = new Date();
+    expiration.setDate(expiration.getDate() + 365);
+    document.cookie= 'sortBy=' + escape(by) +
+                     ';expires=' + expiration.toUTCString();
+    $('ul.comment-ul').each(function(index, ul) {
+      var comments = getChildren($(ul), true);
+      comments = sortComments(comments);
+      appendComments(comments, $(ul).empty());
+    });
+  }
+
+  /**
+   * Function to process a vote when a user clicks an arrow.
+   */
+  function handleVote(link) {
+    if (!opts.voting) {
+      showError("You'll need to login to vote.");
+      return;
+    }
+
+    var id = link.attr('id');
+    if (!id) {
+      // Didn't click on one of the voting arrows.
+      return;
+    }
+    // If it is an unvote, the new vote value is 0,
+    // Otherwise it's 1 for an upvote, or -1 for a downvote.
+    var value = 0;
+    if (id.charAt(1) != 'u') {
+      value = id.charAt(0) == 'u' ? 1 : -1;
+    }
+    // The data to be sent to the server.
+    var d = {
+      comment_id: id.substring(2),
+      value: value
+    };
+
+    // Swap the vote and unvote links.
+    link.hide();
+    $('#' + id.charAt(0) + (id.charAt(1) == 'u' ? 'v' : 'u') + d.comment_id)
+      .show();
+
+    // The div the comment is displayed in.
+    var div = $('div#cd' + d.comment_id);
+    var data = div.data('comment');
+
+    // If this is not an unvote, and the other vote arrow has
+    // already been pressed, unpress it.
+    if ((d.value !== 0) && (data.vote === d.value * -1)) {
+      $('#' + (d.value == 1 ? 'd' : 'u') + 'u' + d.comment_id).hide();
+      $('#' + (d.value == 1 ? 'd' : 'u') + 'v' + d.comment_id).show();
+    }
+
+    // Update the comments rating in the local data.
+    data.rating += (data.vote === 0) ? d.value : (d.value - data.vote);
+    data.vote = d.value;
+    div.data('comment', data);
+
+    // Change the rating text.
+    div.find('.rating:first')
+      .text(data.rating + ' point' + (data.rating == 1 ? '' : 's'));
+
+    // Send the vote information to the server.
+    $.ajax({
+      type: "POST",
+      url: opts.processVoteURL,
+      data: d,
+      error: function(request, textStatus, error) {
+        showError('Oops, there was a problem casting that vote.');
+      }
+    });
+  }
+
+  /**
+   * Open a reply form used to reply to an existing comment.
+   */
+  function openReply(id) {
+    // Swap out the reply link for the hide link
+    $('#rl' + id).hide();
+    $('#cr' + id).show();
+
+    // Add the reply li to the children ul.
+    var div = $(renderTemplate(replyTemplate, {id: id})).hide();
+    $('#cl' + id)
+      .prepend(div)
+      // Setup the submit handler for the reply form.
+      .find('#rf' + id)
+      .submit(function(event) {
+        event.preventDefault();
+        addComment($('#rf' + id));
+        closeReply(id);
+      })
+      .find('input[type=button]')
+      .click(function() {
+        closeReply(id);
+      });
+    div.slideDown('fast', function() {
+      $('#rf' + id).find('textarea').focus();
+    });
+  }
+
+  /**
+   * Close the reply form opened with openReply.
+   */
+  function closeReply(id) {
+    // Remove the reply div from the DOM.
+    $('#rd' + id).slideUp('fast', function() {
+      $(this).remove();
+    });
+
+    // Swap out the hide link for the reply link
+    $('#cr' + id).hide();
+    $('#rl' + id).show();
+  }
+
+  /**
+   * Recursively sort a tree of comments using the comp comparator.
+   */
+  function sortComments(comments) {
+    comments.sort(comp);
+    $.each(comments, function() {
+      this.children = sortComments(this.children);
+    });
+    return comments;
+  }
+
+  /**
+   * Get the children comments from a ul. If recursive is true,
+   * recursively include childrens' children.
+   */
+  function getChildren(ul, recursive) {
+    var children = [];
+    ul.children().children("[id^='cd']")
+      .each(function() {
+        var comment = $(this).data('comment');
+        if (recursive)
+          comment.children = getChildren($(this).find('#cl' + comment.id), true);
+        children.push(comment);
+      });
+    return children;
+  }
+
+  /** Create a div to display a comment in. */
+  function createCommentDiv(comment) {
+    if (!comment.displayed && !opts.moderator) {
+      return $('<div class="moderate">Thank you!  Your comment will show up '
+               + 'once it is has been approved by a moderator.</div>');
+    }
+    // Prettify the comment rating.
+    comment.pretty_rating = comment.rating + ' point' +
+      (comment.rating == 1 ? '' : 's');
+    // Make a class (for displaying not yet moderated comments differently)
+    comment.css_class = comment.displayed ? '' : ' moderate';
+    // Create a div for this comment.
+    var context = $.extend({}, opts, comment);
+    var div = $(renderTemplate(commentTemplate, context));
+
+    // If the user has voted on this comment, highlight the correct arrow.
+    if (comment.vote) {
+      var direction = (comment.vote == 1) ? 'u' : 'd';
+      div.find('#' + direction + 'v' + comment.id).hide();
+      div.find('#' + direction + 'u' + comment.id).show();
+    }
+
+    if (opts.moderator || comment.text != '[deleted]') {
+      div.find('a.reply').show();
+      if (comment.proposal_diff)
+        div.find('#sp' + comment.id).show();
+      if (opts.moderator && !comment.displayed)
+        div.find('#cm' + comment.id).show();
+      if (opts.moderator || (opts.username == comment.username))
+        div.find('#dc' + comment.id).show();
+    }
+    return div;
+  }
+
+  /**
+   * A simple template renderer. Placeholders such as <%id%> are replaced
+   * by context['id'] with items being escaped. Placeholders such as <#id#>
+   * are not escaped.
+   */
+  function renderTemplate(template, context) {
+    var esc = $(document.createElement('div'));
+
+    function handle(ph, escape) {
+      var cur = context;
+      $.each(ph.split('.'), function() {
+        cur = cur[this];
+      });
+      return escape ? esc.text(cur || "").html() : cur;
+    }
+
+    return template.replace(/<([%#])([\w\.]*)\1>/g, function() {
+      return handle(arguments[2], arguments[1] == '%' ? true : false);
+    });
+  }
+
+  /** Flash an error message briefly. */
+  function showError(message) {
+    $(document.createElement('div')).attr({'class': 'popup-error'})
+      .append($(document.createElement('div'))
+               .attr({'class': 'error-message'}).text(message))
+      .appendTo('body')
+      .fadeIn("slow")
+      .delay(2000)
+      .fadeOut("slow");
+  }
+
+  /** Add a link the user uses to open the comments popup. */
+  $.fn.comment = function() {
+    return this.each(function() {
+      var id = $(this).attr('id').substring(1);
+      var count = COMMENT_METADATA[id];
+      var title = count + ' comment' + (count == 1 ? '' : 's');
+      var image = count > 0 ? opts.commentBrightImage : opts.commentImage;
+      var addcls = count == 0 ? ' nocomment' : '';
+      $(this)
+        .append(
+          $(document.createElement('a')).attr({
+            href: '#',
+            'class': 'sphinx-comment-open' + addcls,
+            id: 'ao' + id
+          })
+            .append($(document.createElement('img')).attr({
+              src: image,
+              alt: 'comment',
+              title: title
+            }))
+            .click(function(event) {
+              event.preventDefault();
+              show($(this).attr('id').substring(2));
+            })
+        )
+        .append(
+          $(document.createElement('a')).attr({
+            href: '#',
+            'class': 'sphinx-comment-close hidden',
+            id: 'ah' + id
+          })
+            .append($(document.createElement('img')).attr({
+              src: opts.closeCommentImage,
+              alt: 'close',
+              title: 'close'
+            }))
+            .click(function(event) {
+              event.preventDefault();
+              hide($(this).attr('id').substring(2));
+            })
+        );
+    });
+  };
+
+  var opts = {
+    processVoteURL: '/_process_vote',
+    addCommentURL: '/_add_comment',
+    getCommentsURL: '/_get_comments',
+    acceptCommentURL: '/_accept_comment',
+    deleteCommentURL: '/_delete_comment',
+    commentImage: '/static/_static/comment.png',
+    closeCommentImage: '/static/_static/comment-close.png',
+    loadingImage: '/static/_static/ajax-loader.gif',
+    commentBrightImage: '/static/_static/comment-bright.png',
+    upArrow: '/static/_static/up.png',
+    downArrow: '/static/_static/down.png',
+    upArrowPressed: '/static/_static/up-pressed.png',
+    downArrowPressed: '/static/_static/down-pressed.png',
+    voting: false,
+    moderator: false
+  };
+
+  if (typeof COMMENT_OPTIONS != "undefined") {
+    opts = jQuery.extend(opts, COMMENT_OPTIONS);
+  }
+
+  var popupTemplate = '\
+    <div class="sphinx-comments" id="sc<%id%>">\
+      <p class="sort-options">\
+        Sort by:\
+        <a href="#" class="sort-option byrating">best rated</a>\
+        <a href="#" class="sort-option byascage">newest</a>\
+        <a href="#" class="sort-option byage">oldest</a>\
+      </p>\
+      <div class="comment-header">Comments</div>\
+      <div class="comment-loading" id="cn<%id%>">\
+        loading comments... <img src="<%loadingImage%>" alt="" /></div>\
+      <ul id="cl<%id%>" class="comment-ul"></ul>\
+      <div id="ca<%id%>">\
+      <p class="add-a-comment">Add a comment\
+        (<a href="#" class="comment-markup" id="ab<%id%>">markup</a>):</p>\
+      <div class="comment-markup-box" id="mb<%id%>">\
+        reStructured text markup: <i>*emph*</i>, <b>**strong**</b>, \
+        <tt>``code``</tt>, \
+        code blocks: <tt>::</tt> and an indented block after blank line</div>\
+      <form method="post" id="cf<%id%>" class="comment-form" action="">\
+        <textarea name="comment" cols="80"></textarea>\
+        <p class="propose-button">\
+          <a href="#" id="pc<%id%>" class="show-propose-change">\
+            Propose a change &#9657;\
+          </a>\
+          <a href="#" id="hc<%id%>" class="hide-propose-change">\
+            Propose a change &#9663;\
+          </a>\
+        </p>\
+        <textarea name="proposal" id="pt<%id%>" cols="80"\
+                  spellcheck="false"></textarea>\
+        <input type="submit" value="Add comment" />\
+        <input type="hidden" name="node" value="<%id%>" />\
+        <input type="hidden" name="parent" value="" />\
+      </form>\
+      </div>\
+    </div>';
+
+  var commentTemplate = '\
+    <div id="cd<%id%>" class="sphinx-comment<%css_class%>">\
+      <div class="vote">\
+        <div class="arrow">\
+          <a href="#" id="uv<%id%>" class="vote" title="vote up">\
+            <img src="<%upArrow%>" />\
+          </a>\
+          <a href="#" id="uu<%id%>" class="un vote" title="vote up">\
+            <img src="<%upArrowPressed%>" />\
+          </a>\
+        </div>\
+        <div class="arrow">\
+          <a href="#" id="dv<%id%>" class="vote" title="vote down">\
+            <img src="<%downArrow%>" id="da<%id%>" />\
+          </a>\
+          <a href="#" id="du<%id%>" class="un vote" title="vote down">\
+            <img src="<%downArrowPressed%>" />\
+          </a>\
+        </div>\
+      </div>\
+      <div class="comment-content">\
+        <p class="tagline comment">\
+          <span class="user-id"><%username%></span>\
+          <span class="rating"><%pretty_rating%></span>\
+          <span class="delta"><%time.delta%></span>\
+        </p>\
+        <div class="comment-text comment"><#text#></div>\
+        <p class="comment-opts comment">\
+          <a href="#" class="reply hidden" id="rl<%id%>">reply &#9657;</a>\
+          <a href="#" class="close-reply" id="cr<%id%>">reply &#9663;</a>\
+          <a href="#" id="sp<%id%>" class="show-proposal">proposal &#9657;</a>\
+          <a href="#" id="hp<%id%>" class="hide-proposal">proposal &#9663;</a>\
+          <a href="#" id="dc<%id%>" class="delete-comment hidden">delete</a>\
+          <span id="cm<%id%>" class="moderation hidden">\
+            <a href="#" id="ac<%id%>" class="accept-comment">accept</a>\
+          </span>\
+        </p>\
+        <pre class="proposal" id="pr<%id%>">\
+<#proposal_diff#>\
+        </pre>\
+          <ul class="comment-children" id="cl<%id%>"></ul>\
+        </div>\
+        <div class="clearleft"></div>\
+      </div>\
+    </div>';
+
+  var replyTemplate = '\
+    <li>\
+      <div class="reply-div" id="rd<%id%>">\
+        <form id="rf<%id%>">\
+          <textarea name="comment" cols="80"></textarea>\
+          <input type="submit" value="Add reply" />\
+          <input type="button" value="Cancel" />\
+          <input type="hidden" name="parent" value="<%id%>" />\
+          <input type="hidden" name="node" value="" />\
+        </form>\
+      </div>\
+    </li>';
+
+  $(document).ready(function() {
+    init();
+  });
+})(jQuery);
+
+$(document).ready(function() {
+  // add comment anchors for all paragraphs that are commentable
+  $('.sphinx-has-comment').comment();
+
+  // highlight search words in search results
+  $("div.context").each(function() {
+    var params = $.getQueryParameters();
+    var terms = (params.q) ? params.q[0].split(/\s+/) : [];
+    var result = $(this);
+    $.each(terms, function() {
+      result.highlightText(this.toLowerCase(), 'highlighted');
+    });
+  });
+
+  // directly open comment window if requested
+  var anchor = document.location.hash;
+  if (anchor.substring(0, 9) == '#comment-') {
+    $('#ao' + anchor.substring(9)).click();
+    document.location.hash = '#s' + anchor.substring(9);
+  }
+});
index ea4ca28..5defc00 100644 (file)
@@ -1,5 +1,3 @@
-
-
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
@@ -15,7 +13,7 @@
     
     <script type="text/javascript">
       var DOCUMENTATION_OPTIONS = {
-        URL_ROOT:    '',
+        URL_ROOT:    './',
         VERSION:     '1.0',
         COLLAPSE_INDEX: false,
         FILE_SUFFIX: '.html',
@@ -27,7 +25,7 @@
     <script type="text/javascript" src="_static/doctools.js"></script>
     <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
     <link rel="top" title="Gnuk Documentation 1.0 documentation" href="index.html" />
-    <link rel="prev" title="GnuPG settings for GNOME 3" href="gnome3-gpg-settings.html" /> 
+    <link rel="prev" title="GnuPG settings for GNOME 3.1x and GNOME 3.0" href="gnome3-gpg-settings.html" /> 
   </head>
   <body>
     <div class="related">
@@ -37,7 +35,7 @@
           <a href="genindex.html" title="General Index"
              accesskey="I">index</a></li>
         <li class="right" >
-          <a href="gnome3-gpg-settings.html" title="GnuPG settings for GNOME 3"
+          <a href="gnome3-gpg-settings.html" title="GnuPG settings for GNOME 3.1x and GNOME 3.0"
              accesskey="P">previous</a> |</li>
         <li><a href="index.html">Gnuk Documentation 1.0 documentation</a> &raquo;</li> 
       </ul>
@@ -115,7 +113,7 @@ product ID&#8217; in README.</p>
 
   <h4>Previous topic</h4>
   <p class="topless"><a href="gnome3-gpg-settings.html"
-                        title="previous chapter">GnuPG settings for GNOME 3</a></p>
+                        title="previous chapter">GnuPG settings for GNOME 3.1x and GNOME 3.0</a></p>
   <h3>This Page</h3>
   <ul class="this-page-menu">
     <li><a href="_sources/development.txt"
@@ -145,14 +143,14 @@ product ID&#8217; in README.</p>
           <a href="genindex.html" title="General Index"
              >index</a></li>
         <li class="right" >
-          <a href="gnome3-gpg-settings.html" title="GnuPG settings for GNOME 3"
+          <a href="gnome3-gpg-settings.html" title="GnuPG settings for GNOME 3.1x and GNOME 3.0"
              >previous</a> |</li>
         <li><a href="index.html">Gnuk Documentation 1.0 documentation</a> &raquo;</li> 
       </ul>
     </div>
     <div class="footer">
         &copy; Copyright 2012, NIIBE Yutaka.
-      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.3.
     </div>
   </body>
 </html>
\ No newline at end of file
index b119550..46382ce 100644 (file)
@@ -1,5 +1,3 @@
-
-
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
@@ -15,7 +13,7 @@
     
     <script type="text/javascript">
       var DOCUMENTATION_OPTIONS = {
-        URL_ROOT:    '',
+        URL_ROOT:    './',
         VERSION:     '1.0',
         COLLAPSE_INDEX: false,
         FILE_SUFFIX: '.html',
@@ -83,60 +81,67 @@ device computation power and host software constraints.</p>
 <h2>Generating keys on host PC<a class="headerlink" href="#generating-keys-on-host-pc" title="Permalink to this headline">¶</a></h2>
 <p>Here is the example session to generate main key and a subkey for encryption.</p>
 <p>I invoke GnuPG with <tt class="docutils literal"><span class="pre">--gen-key</span></tt> option.</p>
-<div class="highlight-python"><pre>$ gpg --gen-key
+<div class="highlight-python"><div class="highlight"><pre>$ gpg --gen-key
 gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc.
 This is free software: you are free to change and redistribute it.
-There is NO WARRANTY, to the extent permitted by law.</pre>
+There is NO WARRANTY, to the extent permitted by law.
+</pre></div>
 </div>
 <p>and GnuPG asks kind of key.  Select <tt class="docutils literal"><span class="pre">RSA</span> <span class="pre">and</span> <span class="pre">RSA</span></tt>.</p>
-<div class="highlight-python"><pre>Please select what kind of key you want:
+<div class="highlight-python"><div class="highlight"><pre>Please select what kind of key you want:
    (1) RSA and RSA (default)
    (2) DSA and Elgamal
    (3) DSA (sign only)
    (4) RSA (sign only)
 Your selection? 1
-RSA keys may be between 1024 and 4096 bits long.</pre>
+RSA keys may be between 1024 and 4096 bits long.
+</pre></div>
 </div>
 <p>and select 2048-bit (as Gnuk Token only supports this).</p>
-<div class="highlight-python"><pre>What keysize do you want? (2048)
-Requested keysize is 2048 bits</pre>
+<div class="highlight-python"><div class="highlight"><pre>What keysize do you want? (2048)
+Requested keysize is 2048 bits
+</pre></div>
 </div>
 <p>and select expiration of the key.</p>
-<div class="highlight-python"><pre>Please specify how long the key should be valid.
+<div class="highlight-python"><div class="highlight"><pre>Please specify how long the key should be valid.
          0 = key does not expire
       &lt;n&gt;  = key expires in n days
       &lt;n&gt;w = key expires in n weeks
       &lt;n&gt;m = key expires in n months
       &lt;n&gt;y = key expires in n years
 Key is valid for? (0) 0
-Key does not expire at all</pre>
+Key does not expire at all
+</pre></div>
 </div>
 <p>Confirm key types, bitsize and expiration.</p>
-<div class="highlight-python"><pre>Is this correct? (y/N) y</pre>
+<div class="highlight-python"><div class="highlight"><pre>Is this correct? (y/N) y
+</pre></div>
 </div>
 <p>Then enter user ID.</p>
-<div class="highlight-python"><pre>You need a user ID to identify your key; the software constructs the user ID
+<div class="highlight-python"><div class="highlight"><pre>You need a user ID to identify your key; the software constructs the user ID
 from the Real Name, Comment and Email Address in this form:
-    "Heinrich Heine (Der Dichter) &lt;heinrichh@duesseldorf.de&gt;"
+    &quot;Heinrich Heine (Der Dichter) &lt;heinrichh@duesseldorf.de&gt;&quot;
 
 Real name: Niibe Yutaka
 Email address: gniibe@fsij.org
 Comment:
 You selected this USER-ID:
-    "Niibe Yutaka &lt;gniibe@fsij.org&gt;"
+    &quot;Niibe Yutaka &lt;gniibe@fsij.org&gt;&quot;
 
-Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o</pre>
+Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
+</pre></div>
 </div>
 <p>and enter passphrase for this <strong>key on host PC</strong>.
 Note that this is a passphrase for the key on host PC.
 It is different thing to the passphrase of Gnuk Token.</p>
 <p>We enter two same inputs two times
 (once for passphrase input, and another for confirmation).</p>
-<div class="highlight-python"><pre>You need a Passphrase to protect your secret key.
-&lt;PASSWORD-KEY-ON-PC&gt;</pre>
+<div class="highlight-python"><div class="highlight"><pre>You need a Passphrase to protect your secret key.
+&lt;PASSWORD-KEY-ON-PC&gt;
+</pre></div>
 </div>
 <p>Then, GnuPG generate keys.  It takes some time.</p>
-<div class="highlight-python"><pre>We need to generate a lot of random bytes. It is a good idea to perform
+<div class="highlight-python"><div class="highlight"><pre>We need to generate a lot of random bytes. It is a good idea to perform
 some other action (type on the keyboard, move the mouse, utilize the
 disks) during the prime generation; this gives the random number
 generator a better chance to gain enough entropy.
@@ -160,14 +165,15 @@ pub   2048R/4CA7BABE 2010-10-15
       Key fingerprint = 1241 24BD 3B48 62AF 7A0A  42F1 00B4 5EBD 4CA7 BABE
 uid                  Niibe Yutaka &lt;gniibe@fsij.org&gt;
 sub   2048R/084239CF 2010-10-15
-$</pre>
+$
+</pre></div>
 </div>
 <p>Done.</p>
 <p>Then, we create authentication subkey.
 Authentication subkey is not that common,
 but very useful (for SSH authentication).
 As it is not that common, we need <tt class="docutils literal"><span class="pre">--expert</span></tt> option for GnuPG.</p>
-<div class="highlight-python"><pre>$ gpg --expert --edit-key 4CA7BABE
+<div class="highlight-python"><div class="highlight"><pre>$ gpg --expert --edit-key 4CA7BABE
 gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc.
 This is free software: you are free to change and redistribute it.
 There is NO WARRANTY, to the extent permitted by law.
@@ -179,37 +185,40 @@ pub  2048R/4CA7BABE  created: 2010-10-15  expires: never       usage: SC
 sub  2048R/084239CF  created: 2010-10-15  expires: never       usage: E
 [ultimate] (1). Niibe Yutaka &lt;gniibe@fsij.org&gt;
 
-gpg&gt;</pre>
+gpg&gt;
+</pre></div>
 </div>
 <p>Here, it displays that there are main key and a subkey.
 It prompts sub-command with <tt class="docutils literal"><span class="pre">gpg&gt;</span></tt> .</p>
 <p>Here, we enter <tt class="docutils literal"><span class="pre">addkey</span></tt> sub-command.
 Then, we enter the passphrase of <strong>key on host PC</strong>.
 It&#8217;s the one we entered above as &lt;PASSWORD-KEY-ON-PC&gt;.</p>
-<div class="highlight-python"><pre>gpg&gt; addkey
+<div class="highlight-python"><div class="highlight"><pre>gpg&gt; addkey
 Key is protected.
 
 You need a passphrase to unlock the secret key for
-user: "Niibe Yutaka &lt;gniibe@fsij.org&gt;"
+user: &quot;Niibe Yutaka &lt;gniibe@fsij.org&gt;&quot;
 2048-bit RSA key, ID 4CA7BABE, created 2010-10-15
 &lt;PASSWORD-KEY-ON-PC&gt;
-gpg: gpg-agent is not available in this session</pre>
+gpg: gpg-agent is not available in this session
+</pre></div>
 </div>
 <p>GnuPG asks kind of key.  We select <tt class="docutils literal"><span class="pre">RSA</span> <span class="pre">(set</span> <span class="pre">your</span> <span class="pre">own</span> <span class="pre">capabilities)</span></tt>.</p>
-<div class="highlight-python"><pre>Please select what kind of key you want:
+<div class="highlight-python"><div class="highlight"><pre>Please select what kind of key you want:
    (3) DSA (sign only)
    (4) RSA (sign only)
    (5) Elgamal (encrypt only)
    (6) RSA (encrypt only)
    (7) DSA (set your own capabilities)
    (8) RSA (set your own capabilities)
-Your selection? 8</pre>
+Your selection? 8
+</pre></div>
 </div>
 <p>And select <tt class="docutils literal"><span class="pre">Authenticate</span></tt> for the capabilities for this key.
 Initially, it&#8217;s <tt class="docutils literal"><span class="pre">Sign</span></tt> and  <tt class="docutils literal"><span class="pre">Encrypt</span></tt>.
 I need to deselect <tt class="docutils literal"><span class="pre">Sign</span></tt> and <tt class="docutils literal"><span class="pre">Encrypt</span></tt>, and select <tt class="docutils literal"><span class="pre">Authenticate</span></tt>.
 To do that, I enter <tt class="docutils literal"><span class="pre">s</span></tt>, <tt class="docutils literal"><span class="pre">e</span></tt>, and <tt class="docutils literal"><span class="pre">a</span></tt>.</p>
-<div class="highlight-python"><pre>Possible actions for a RSA key: Sign Encrypt Authenticate
+<div class="highlight-python"><div class="highlight"><pre>Possible actions for a RSA key: Sign Encrypt Authenticate
 Current allowed actions: Sign Encrypt
 
    (S) Toggle the sign capability
@@ -245,15 +254,17 @@ Current allowed actions: Authenticate
    (S) Toggle the sign capability
    (E) Toggle the encrypt capability
    (A) Toggle the authenticate capability
-   (Q) Finished</pre>
+   (Q) Finished
+</pre></div>
 </div>
 <p>OK, we set the capability of <tt class="docutils literal"><span class="pre">Authenticate</span></tt>.
 We enter <tt class="docutils literal"><span class="pre">q</span></tt> to finish setting capabilities.</p>
-<div class="highlight-python"><pre>Your selection? q</pre>
+<div class="highlight-python"><div class="highlight"><pre>Your selection? q
+</pre></div>
 </div>
 <p>GnuPG asks bitsize and expiration, we enter 2048 for bitsize and no expiration.
 Then, we confirm that we really create the key.</p>
-<div class="highlight-python"><pre>RSA keys may be between 1024 and 4096 bits long.
+<div class="highlight-python"><div class="highlight"><pre>RSA keys may be between 1024 and 4096 bits long.
 What keysize do you want? (2048)
 Requested keysize is 2048 bits
 Please specify how long the key should be valid.
@@ -265,10 +276,11 @@ Please specify how long the key should be valid.
 Key is valid for? (0) 0
 Key does not expire at all
 Is this correct? (y/N) y
-Really create? (y/N) y</pre>
+Really create? (y/N) y
+</pre></div>
 </div>
 <p>Then, GnuPG generate the key.</p>
-<div class="highlight-python"><pre>We need to generate a lot of random bytes. It is a good idea to perform
+<div class="highlight-python"><div class="highlight"><pre>We need to generate a lot of random bytes. It is a good idea to perform
 some other action (type on the keyboard, move the mouse, utilize the
 disks) during the prime generation; this gives the random number
 generator a better chance to gain enough entropy.
@@ -281,11 +293,13 @@ sub  2048R/084239CF  created: 2010-10-15  expires: never       usage: E
 sub  2048R/5BB065DC  created: 2010-10-22  expires: never       usage: A
 [ultimate] (1). Niibe Yutaka &lt;gniibe@fsij.org&gt;
 
-gpg&gt;</pre>
+gpg&gt;
+</pre></div>
 </div>
 <p>We save the key (to the storage of the host PC.</p>
-<div class="highlight-python"><pre>gpg&gt; save
-$</pre>
+<div class="highlight-python"><div class="highlight"><pre>gpg&gt; save
+$
+</pre></div>
 </div>
 <p>Now, we have three keys (one primary key for signature and certification,
 subkey for encryption, and another subkey for authentication).</p>
@@ -293,11 +307,13 @@ subkey for encryption, and another subkey for authentication).</p>
 <div class="section" id="publishing-public-key">
 <h2>Publishing public key<a class="headerlink" href="#publishing-public-key" title="Permalink to this headline">¶</a></h2>
 <p>We make a file for the public key by <tt class="docutils literal"><span class="pre">--export</span></tt> option of GnuPG.</p>
-<div class="highlight-python"><pre>$ gpg --armor --output &lt;YOUR-KEY&gt;.asc --export &lt;YOUR-KEY-ID&gt;</pre>
+<div class="highlight-python"><div class="highlight"><pre>$ gpg --armor --output &lt;YOUR-KEY&gt;.asc --export &lt;YOUR-KEY-ID&gt;
+</pre></div>
 </div>
 <p>We can publish the file by web server.  Or we can publish the key
 to a keyserver, by invoking GnuPG with <tt class="docutils literal"><span class="pre">--send-keys</span></tt> option.</p>
-<div class="highlight-python"><pre>$ gpg --keyserver pool.sks-keyservers.net --send-keys &lt;YOUR-KEY-ID&gt;</pre>
+<div class="highlight-python"><div class="highlight"><pre>$ gpg --keyserver pool.sks-keyservers.net --send-keys &lt;YOUR-KEY-ID&gt;
+</pre></div>
 </div>
 <p>Here, pool.sks-keyservers.net is a keyserver, which is widely used.</p>
 </div>
@@ -316,11 +332,13 @@ You have been warned.</p>
 <p>To make ASCII backup for private key,
 invokde GnuPG with <tt class="docutils literal"><span class="pre">--armor</span></tt> option and <tt class="docutils literal"><span class="pre">--export-secret-keys</span></tt>
 specifying the key identifier.</p>
-<div class="highlight-python"><pre>$ gpg --armor --output &lt;YOUR-SECRET&gt;.asc --export-secret-keys &lt;YOUR-KEY-ID&gt;</pre>
+<div class="highlight-python"><div class="highlight"><pre>$ gpg --armor --output &lt;YOUR-SECRET&gt;.asc --export-secret-keys &lt;YOUR-KEY-ID&gt;
+</pre></div>
 </div>
 <p>From the backup,
 we can recover privet key by invoking GnuPG with <tt class="docutils literal"><span class="pre">--import</span></tt> option.</p>
-<div class="highlight-python"><pre>$ gpg --import &lt;YOUR-SECRET&gt;.asc</pre>
+<div class="highlight-python"><div class="highlight"><pre>$ gpg --import &lt;YOUR-SECRET&gt;.asc
+</pre></div>
 </div>
 </div>
 </div>
@@ -387,7 +405,7 @@ we can recover privet key by invoking GnuPG with <tt class="docutils literal"><s
     </div>
     <div class="footer">
         &copy; Copyright 2012, NIIBE Yutaka.
-      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.3.
     </div>
   </body>
 </html>
\ No newline at end of file
index 4a91b73..8cb4d41 100644 (file)
@@ -1,7 +1,4 @@
 
-
-
-
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
@@ -17,7 +14,7 @@
     
     <script type="text/javascript">
       var DOCUMENTATION_OPTIONS = {
-        URL_ROOT:    '',
+        URL_ROOT:    './',
         VERSION:     '1.0',
         COLLAPSE_INDEX: false,
         FILE_SUFFIX: '.html',
@@ -90,7 +87,7 @@
     </div>
     <div class="footer">
         &copy; Copyright 2012, NIIBE Yutaka.
-      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.3.
     </div>
   </body>
 </html>
\ No newline at end of file
index 2155cd7..9136d3b 100644 (file)
@@ -1,5 +1,3 @@
-
-
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
@@ -8,14 +6,14 @@
   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
     
-    <title>GnuPG settings for GNOME 3 &mdash; Gnuk Documentation 1.0 documentation</title>
+    <title>GnuPG settings for GNOME 3.1x and GNOME 3.0 &mdash; Gnuk Documentation 1.0 documentation</title>
     
     <link rel="stylesheet" href="_static/default.css" type="text/css" />
     <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
     
     <script type="text/javascript">
       var DOCUMENTATION_OPTIONS = {
-        URL_ROOT:    '',
+        URL_ROOT:    './',
         VERSION:     '1.0',
         COLLAPSE_INDEX: false,
         FILE_SUFFIX: '.html',
@@ -27,7 +25,8 @@
     <script type="text/javascript" src="_static/doctools.js"></script>
     <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
     <link rel="top" title="Gnuk Documentation 1.0 documentation" href="index.html" />
-    <link rel="prev" title="GnuPG settings" href="gpg-settings.html" /> 
+    <link rel="next" title="Development Environment" href="development.html" />
+    <link rel="prev" title="Using Gnuk Token with another computer" href="using-gnuk-token-with-another-computer.html" /> 
   </head>
   <body>
     <div class="related">
           <a href="genindex.html" title="General Index"
              accesskey="I">index</a></li>
         <li class="right" >
-          <a href="gpg-settings.html" title="GnuPG settings"
+          <a href="development.html" title="Development Environment"
+             accesskey="N">next</a> |</li>
+        <li class="right" >
+          <a href="using-gnuk-token-with-another-computer.html" title="Using Gnuk Token with another computer"
              accesskey="P">previous</a> |</li>
         <li><a href="index.html">Gnuk Documentation 1.0 documentation</a> &raquo;</li> 
       </ul>
         <div class="bodywrapper">
           <div class="body">
             
-  <div class="section" id="gnupg-settings-for-gnome-3">
-<h1>GnuPG settings for GNOME 3<a class="headerlink" href="#gnupg-settings-for-gnome-3" title="Permalink to this headline">¶</a></h1>
-<p>In the article <a class="reference external" href="gpg-settings">GnuPG settings</a>, I wrote how I disable GNOME-keyrings for SSH.</p>
+  <div class="section" id="gnupg-settings-for-gnome-3-1x-and-gnome-3-0">
+<h1>GnuPG settings for GNOME 3.1x and GNOME 3.0<a class="headerlink" href="#gnupg-settings-for-gnome-3-1x-and-gnome-3-0" title="Permalink to this headline">¶</a></h1>
+<p>In the section <a class="reference external" href="gpg-settings">GnuPG settings</a>, I wrote how I disable GNOME-keyrings for SSH.</p>
 <p>It was for GNOME 2.  The old days was good, we just disabled GNOME-keyrings
 interference to SSH and customizing our desktop was easy for GNU and UNIX users.</p>
-<div class="section" id="gnome-keyrings-in-gnome-3">
-<h2>GNOME keyrings in GNOME 3<a class="headerlink" href="#gnome-keyrings-in-gnome-3" title="Permalink to this headline">¶</a></h2>
-<p>It seems that it is more integrated into the desktop.
-It is difficult to kill it.  It would be possible to kill it simply,
-but then, I can&#8217;t use, say, wi-fi access (which needs to access &#8220;secrets&#8221;)
-any more.</p>
-<p>We can&#8217;t use GNOME configuration tool to disable interference by
-GNOME keyrings any more.  It seems that desktop should not have
-customization these days.</p>
+<div class="section" id="gnome-keyrings-in-gnome-3-1x">
+<h2>GNOME keyrings in GNOME 3.1x<a class="headerlink" href="#gnome-keyrings-in-gnome-3-1x" title="Permalink to this headline">¶</a></h2>
+<p>In the files /etc/xdg/autostart/gnome-keyring-ssh.desktop
+and /etc/xdg/autostart/gnome-keyring-gpg.desktop,
+we have a line something like:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">OnlyShowIn</span><span class="o">=</span><span class="n">GNOME</span><span class="p">;</span><span class="n">Unity</span><span class="p">;</span><span class="n">MATE</span><span class="p">;</span>
+</pre></div>
 </div>
-<div class="section" id="gnome-session-properties">
-<h2>GNOME-SESSION-PROPERTIES<a class="headerlink" href="#gnome-session-properties" title="Permalink to this headline">¶</a></h2>
-<p>After struggling some hours, I figured out it is GNOME-SESSION-PROPERTIES
-to disable the interference.  Invoking:</p>
-<div class="highlight-python"><pre>$ gnome-session-properties</pre>
+<p>Please edit this line to:</p>
+<div class="highlight-python"><div class="highlight"><pre>OnlyShowIn=
+</pre></div>
+</div>
+<p>Then, no desktop environment invokes gnome-keyring for ssh and gpg.  I think that it is The Right Thing.</p>
+</div>
+<div class="section" id="gnome-keyrings-in-gnome-3-0-by-gnome-session-properties">
+<h2>GNOME keyrings in GNOME 3.0 by GNOME-SESSION-PROPERTIES<a class="headerlink" href="#gnome-keyrings-in-gnome-3-0-by-gnome-session-properties" title="Permalink to this headline">¶</a></h2>
+<p>We can&#8217;t use GNOME configuration tool (like GNOME 2) to disable interference by
+GNOME keyrings in GNOME 3.0.</p>
+<p>It is GNOME-SESSION-PROPERTIES to disable the interference.  Invoking:</p>
+<div class="highlight-python"><div class="highlight"><pre>$ gnome-session-properties
+</pre></div>
 </div>
 <p>and at the tab of &#8220;Startup Programs&#8221;, I removed radio check buttons
 for &#8220;GPG Password Agent&#8221; and &#8220;SSH Key Agent&#8221;.</p>
-<p>Now, I use gpg-agent for GnuPG Agent and SSH agent with Gnuk Token.</p>
+<p>Then, I can use proper gpg-agent for GnuPG Agent Service and SSH Agent Service with Gnuk Token in GNOME 3.0.</p>
 </div>
 </div>
 
@@ -83,16 +91,19 @@ for &#8220;GPG Password Agent&#8221; and &#8220;SSH Key Agent&#8221;.</p>
         <div class="sphinxsidebarwrapper">
   <h3><a href="index.html">Table Of Contents</a></h3>
   <ul>
-<li><a class="reference internal" href="#">GnuPG settings for GNOME 3</a><ul>
-<li><a class="reference internal" href="#gnome-keyrings-in-gnome-3">GNOME keyrings in GNOME 3</a></li>
-<li><a class="reference internal" href="#gnome-session-properties">GNOME-SESSION-PROPERTIES</a></li>
+<li><a class="reference internal" href="#">GnuPG settings for GNOME 3.1x and GNOME 3.0</a><ul>
+<li><a class="reference internal" href="#gnome-keyrings-in-gnome-3-1x">GNOME keyrings in GNOME 3.1x</a></li>
+<li><a class="reference internal" href="#gnome-keyrings-in-gnome-3-0-by-gnome-session-properties">GNOME keyrings in GNOME 3.0 by GNOME-SESSION-PROPERTIES</a></li>
 </ul>
 </li>
 </ul>
 
   <h4>Previous topic</h4>
-  <p class="topless"><a href="gpg-settings.html"
-                        title="previous chapter">GnuPG settings</a></p>
+  <p class="topless"><a href="using-gnuk-token-with-another-computer.html"
+                        title="previous chapter">Using Gnuk Token with another computer</a></p>
+  <h4>Next topic</h4>
+  <p class="topless"><a href="development.html"
+                        title="next chapter">Development Environment</a></p>
   <h3>This Page</h3>
   <ul class="this-page-menu">
     <li><a href="_sources/gnome3-gpg-settings.txt"
@@ -122,14 +133,17 @@ for &#8220;GPG Password Agent&#8221; and &#8220;SSH Key Agent&#8221;.</p>
           <a href="genindex.html" title="General Index"
              >index</a></li>
         <li class="right" >
-          <a href="gpg-settings.html" title="GnuPG settings"
+          <a href="development.html" title="Development Environment"
+             >next</a> |</li>
+        <li class="right" >
+          <a href="using-gnuk-token-with-another-computer.html" title="Using Gnuk Token with another computer"
              >previous</a> |</li>
         <li><a href="index.html">Gnuk Documentation 1.0 documentation</a> &raquo;</li> 
       </ul>
     </div>
     <div class="footer">
         &copy; Copyright 2012, NIIBE Yutaka.
-      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.3.
     </div>
   </body>
 </html>
\ No newline at end of file
index f5c757d..82bbca9 100644 (file)
@@ -1,5 +1,3 @@
-
-
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
@@ -15,7 +13,7 @@
     
     <script type="text/javascript">
       var DOCUMENTATION_OPTIONS = {
-        URL_ROOT:    '',
+        URL_ROOT:    './',
         VERSION:     '1.0',
         COLLAPSE_INDEX: false,
         FILE_SUFFIX: '.html',
 <h1>Key import from PC to Gnuk Token (no removal)<a class="headerlink" href="#key-import-from-pc-to-gnuk-token-no-removal" title="Permalink to this headline">¶</a></h1>
 <p>This document describes how I put my <strong>keys on PC</strong> to the Token
 without removing keys from PC.</p>
-<p>The difference is just not-to-save changes after key imports.</p>
-<p>After personalization, I put my keys into the Token.</p>
-<p>Here is the log.</p>
-<p>I invoke GnuPG with my key (4ca7babe) and with <tt class="docutils literal"><span class="pre">--homedir</span></tt> option
-to specify the directory which contains my secret keys.</p>
-<div class="highlight-python"><pre>$ gpg --homedir=/home/gniibe/tmp/gnuk-testing-dir --edit-key 4ca7babe
-gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc.
-This is free software: you are free to change and redistribute it.
-There is NO WARRANTY, to the extent permitted by law.
-
-Secret key is available.
-
-pub  2048R/4CA7BABE  created: 2010-10-15  expires: never       usage: SC
-                     trust: ultimate      validity: ultimate
-sub  2048R/084239CF  created: 2010-10-15  expires: never       usage: E
-sub  2048R/5BB065DC  created: 2010-10-22  expires: never       usage: A
-[ultimate] (1). NIIBE Yutaka &lt;gniibe@fsij.org&gt;</pre>
-</div>
-<p>Then, GnuPG enters its own command interaction mode.  The prompt is <tt class="docutils literal"><span class="pre">gpg&gt;</span></tt>.
-To enable <tt class="docutils literal"><span class="pre">keytocard</span></tt> command, I type <tt class="docutils literal"><span class="pre">toggle</span></tt> command.</p>
-<div class="highlight-python"><pre>gpg&gt; toggle
-
-sec  2048R/4CA7BABE  created: 2010-10-15  expires: never
-ssb  2048R/084239CF  created: 2010-10-15  expires: never
-ssb  2048R/5BB065DC  created: 2010-10-22  expires: never
-(1)  NIIBE Yutaka &lt;gniibe@fsij.org&gt;</pre>
-</div>
-<p>Firstly, I import my primary key into Gnuk Token.
-I type <tt class="docutils literal"><span class="pre">keytocard</span></tt> command, answer <tt class="docutils literal"><span class="pre">y</span></tt> to confirm keyimport,
-and type <tt class="docutils literal"><span class="pre">1</span></tt> to say it&#8217;s signature key.</p>
-<div class="highlight-python"><pre>gpg&gt; keytocard
-Really move the primary key? (y/N) y
-Signature key ....: [none]
-Encryption key....: [none]
-Authentication key: [none]
-
-Please select where to store the key:
-   (1) Signature key
-   (3) Authentication key
-Your selection? 1</pre>
-</div>
-<p>Then, GnuPG asks two passwords.  One is the passphrase of <strong>keys on PC</strong>
-and another is the password of <strong>Gnuk Token</strong>.  Note that the password of
-the token and the password of the keys on PC are different things,
-although they can be same.</p>
-<p>Here, I assume that Gnuk Token&#8217;s admin password of factory setting (12345678).</p>
-<p>I enter these passwords.</p>
-<div class="highlight-python"><pre>You need a passphrase to unlock the secret key for
-user: "NIIBE Yutaka &lt;gniibe@fsij.org&gt;"
-2048-bit RSA key, ID 4CA7BABE, created 2010-10-15
-&lt;PASSWORD-KEY-4CA7BABE&gt;
-gpg: writing new key
-gpg: 3 Admin PIN attempts remaining before card is permanently locked
-
-Please enter the Admin PIN
-Enter Admin PIN: 12345678
-
-sec  2048R/4CA7BABE  created: 2010-10-15  expires: never
-                     card-no: F517 00000001
-ssb  2048R/084239CF  created: 2010-10-15  expires: never
-ssb  2048R/5BB065DC  created: 2010-10-22  expires: never
-(1)  NIIBE Yutaka &lt;gniibe@fsij.org&gt;</pre>
-</div>
-<p>The primary key is now on the Token and GnuPG says its card-no (F517 00000001),
-where F517 is the vendor ID of FSIJ.</p>
-<p>Secondly, I import my subkey of encryption.  I select key number &#8216;1&#8217;.</p>
-<div class="highlight-python"><pre>gpg&gt; key 1
-
-sec  2048R/4CA7BABE  created: 2010-10-15  expires: never
-                     card-no: F517 00000001
-ssb* 2048R/084239CF  created: 2010-10-15  expires: never
-ssb  2048R/5BB065DC  created: 2010-10-22  expires: never
-(1)  NIIBE Yutaka &lt;gniibe@fsij.org&gt;</pre>
-</div>
-<p>You can see that the subkey is marked by &#8216;*&#8217;.
-I type <tt class="docutils literal"><span class="pre">keytocard</span></tt> command to import this subkey to Gnuk Token.
-I select <tt class="docutils literal"><span class="pre">2</span></tt> as it&#8217;s encryption key.</p>
-<div class="highlight-python"><pre>gpg&gt; keytocard
-Signature key ....: [none]
-Encryption key....: [none]
-Authentication key: [none]
-
-Please select where to store the key:
-   (2) Encryption key
-Your selection? 2</pre>
-</div>
-<p>Then, GnuPG asks the passphrase of <strong>keys on PC</strong> again.  I enter.</p>
-<div class="highlight-python"><pre>You need a passphrase to unlock the secret key for
-user: "NIIBE Yutaka &lt;gniibe@fsij.org&gt;"
-2048-bit RSA key, ID 084239CF, created 2010-10-15
-&lt;PASSWORD-KEY-4CA7BABE&gt;
-gpg: writing new key
-
-sec  2048R/4CA7BABE  created: 2010-10-15  expires: never
-                     card-no: F517 00000001
-ssb* 2048R/084239CF  created: 2010-10-15  expires: never
-                     card-no: F517 00000001
-ssb  2048R/5BB065DC  created: 2010-10-22  expires: never
-(1)  NIIBE Yutaka &lt;gniibe@fsij.org&gt;</pre>
-</div>
-<p>The sub key is now on the Token and GnuPG says its card-no for it.</p>
-<p>I type <tt class="docutils literal"><span class="pre">key</span> <span class="pre">1</span></tt> to deselect key number &#8216;1&#8217;.</p>
-<div class="highlight-python"><pre>gpg&gt; key 1
-
-sec  2048R/4CA7BABE  created: 2010-10-15  expires: never
-                     card-no: F517 00000001
-ssb  2048R/084239CF  created: 2010-10-15  expires: never
-                     card-no: F517 00000001
-ssb  2048R/5BB065DC  created: 2010-10-22  expires: never
-(1)  NIIBE Yutaka &lt;gniibe@fsij.org&gt;</pre>
-</div>
-<p>Thirdly, I select sub key of authentication which has key number &#8216;2&#8217;.</p>
-<div class="highlight-python"><pre>gpg&gt; key 2
-
-sec  2048R/4CA7BABE  created: 2010-10-15  expires: never
-                     card-no: F517 00000001
-ssb  2048R/084239CF  created: 2010-10-15  expires: never
-                     card-no: F517 00000001
-ssb* 2048R/5BB065DC  created: 2010-10-22  expires: never
-(1)  NIIBE Yutaka &lt;gniibe@fsij.org&gt;</pre>
-</div>
-<p>You can see that the subkey number &#8216;2&#8217; is marked by &#8216;*&#8217;.
-I type <tt class="docutils literal"><span class="pre">keytocard</span></tt> command to import this subkey to Gnuk Token.
-I select <tt class="docutils literal"><span class="pre">3</span></tt> as it&#8217;s authentication key.</p>
-<div class="highlight-python"><pre>gpg&gt; keytocard
-Signature key ....: [none]
-Encryption key....: [none]
-Authentication key: [none]
-
-Please select where to store the key:
-   (3) Authentication key
-Your selection? 3</pre>
-</div>
-<p>Then, GnuPG asks the passphrase of <strong>keys on PC</strong> again.  I enter.</p>
-<div class="highlight-python"><pre>You need a passphrase to unlock the secret key for
-user: "NIIBE Yutaka &lt;gniibe@fsij.org&gt;"
-2048-bit RSA key, ID 5BB065DC, created 2010-10-22
-&lt;PASSWORD-KEY-4CA7BABE&gt;
-gpg: writing new key
-
-sec  2048R/4CA7BABE  created: 2010-10-15  expires: never
-                     card-no: F517 00000001
-ssb  2048R/084239CF  created: 2010-10-15  expires: never
-                     card-no: F517 00000001
-ssb* 2048R/5BB065DC  created: 2010-10-22  expires: never
-                     card-no: F517 00000001
-(1)  NIIBE Yutaka &lt;gniibe@fsij.org&gt;</pre>
-</div>
-<p>The sub key is now on the Token and GnuPG says its card-no for it.</p>
+<p>The difference is only the last step.
+I don&#8217;t save changes on PC after keytocard.</p>
+<p>For the steps before the last step, please see <a href="#id1"><span class="problematic" id="id2">`keytocard with removing keys on PC`_</span></a>.</p>
+<p>Here is the session log of the last step.</p>
 <p>Lastly, I quit GnuPG.  Note that I <strong>don&#8217;t</strong> save changes.</p>
-<div class="highlight-python"><pre>gpg&gt; quit
+<div class="highlight-python"><div class="highlight"><pre>gpg&gt; quit
 Save changes? (y/N) n
 Quit without saving? (y/N) y
-$</pre>
+$
+</pre></div>
 </div>
 <p>All keys are imported to Gnuk Token now.
 Still, secret keys are available on PC.</p>
@@ -266,7 +120,7 @@ Still, secret keys are available on PC.</p>
     </div>
     <div class="footer">
         &copy; Copyright 2012, NIIBE Yutaka.
-      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.3.
     </div>
   </body>
 </html>
\ No newline at end of file
index 952aadf..ee2cfe5 100644 (file)
@@ -1,5 +1,3 @@
-
-
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
@@ -15,7 +13,7 @@
     
     <script type="text/javascript">
       var DOCUMENTATION_OPTIONS = {
-        URL_ROOT:    '',
+        URL_ROOT:    './',
         VERSION:     '1.0',
         COLLAPSE_INDEX: false,
         FILE_SUFFIX: '.html',
@@ -61,13 +59,14 @@ so please be careful.</p>
 <p>If you want to import same keys to multiple Tokens,
 please copy <tt class="docutils literal"><span class="pre">.gnupg</span></tt> directory beforehand.</p>
 <p>In my case, I do something like following:</p>
-<div class="highlight-python"><pre>$ cp -a .gnupg tmp/gnuk-testing-dir</pre>
+<div class="highlight-python"><div class="highlight"><pre>$ cp -a .gnupg tmp/gnuk-testing-dir
+</pre></div>
 </div>
 <p>See <a class="reference external" href="gnuk-keytocard-noremoval">another document</a> to import keys to the Token from copied directory.</p>
 <p>After personalization, I put my keys into the Token.</p>
-<p>Here is the log.</p>
+<p>Here is the session log.</p>
 <p>I invoke GnuPG with my key (4ca7babe).</p>
-<div class="highlight-python"><pre>$ gpg --edit-key 4ca7babe
+<div class="highlight-python"><div class="highlight"><pre>$ gpg --edit-key 4ca7babe
 gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc.
 This is free software: you are free to change and redistribute it.
 There is NO WARRANTY, to the extent permitted by law.
@@ -78,21 +77,23 @@ pub  2048R/4CA7BABE  created: 2010-10-15  expires: never       usage: SC
                      trust: ultimate      validity: ultimate
 sub  2048R/084239CF  created: 2010-10-15  expires: never       usage: E
 sub  2048R/5BB065DC  created: 2010-10-22  expires: never       usage: A
-[ultimate] (1). NIIBE Yutaka &lt;gniibe@fsij.org&gt;</pre>
+[ultimate] (1). NIIBE Yutaka &lt;gniibe@fsij.org&gt;
+</pre></div>
 </div>
 <p>Then, GnuPG enters its own command interaction mode.  The prompt is <tt class="docutils literal"><span class="pre">gpg&gt;</span></tt>.
 To enable <tt class="docutils literal"><span class="pre">keytocard</span></tt> command, I type <tt class="docutils literal"><span class="pre">toggle</span></tt> command.</p>
-<div class="highlight-python"><pre>gpg&gt; toggle
+<div class="highlight-python"><div class="highlight"><pre>gpg&gt; toggle
 
 sec  2048R/4CA7BABE  created: 2010-10-15  expires: never
 ssb  2048R/084239CF  created: 2010-10-15  expires: never
 ssb  2048R/5BB065DC  created: 2010-10-22  expires: never
-(1)  NIIBE Yutaka &lt;gniibe@fsij.org&gt;</pre>
+(1)  NIIBE Yutaka &lt;gniibe@fsij.org&gt;
+</pre></div>
 </div>
 <p>Firstly, I import my primary key into Gnuk Token.
 I type <tt class="docutils literal"><span class="pre">keytocard</span></tt> command, answer <tt class="docutils literal"><span class="pre">y</span></tt> to confirm keyimport,
 and type <tt class="docutils literal"><span class="pre">1</span></tt> to say it&#8217;s signature key.</p>
-<div class="highlight-python"><pre>gpg&gt; keytocard
+<div class="highlight-python"><div class="highlight"><pre>gpg&gt; keytocard
 Really move the primary key? (y/N) y
 Signature key ....: [none]
 Encryption key....: [none]
@@ -101,7 +102,8 @@ Authentication key: [none]
 Please select where to store the key:
    (1) Signature key
    (3) Authentication key
-Your selection? 1</pre>
+Your selection? 1
+</pre></div>
 </div>
 <p>Then, GnuPG asks two passwords.  One is the passphrase of <strong>keys on PC</strong>
 and another is the password of <strong>Gnuk Token</strong>.  Note that the password of
@@ -109,8 +111,8 @@ the token and the password of the keys on PC are different things,
 although they can be same.</p>
 <p>Here, I assume that Gnuk Token&#8217;s admin password of factory setting (12345678).</p>
 <p>I enter these passwords.</p>
-<div class="highlight-python"><pre>You need a passphrase to unlock the secret key for
-user: "NIIBE Yutaka &lt;gniibe@fsij.org&gt;"
+<div class="highlight-python"><div class="highlight"><pre>You need a passphrase to unlock the secret key for
+user: &quot;NIIBE Yutaka &lt;gniibe@fsij.org&gt;&quot;
 2048-bit RSA key, ID 4CA7BABE, created 2010-10-15
 &lt;PASSWORD-KEY-4CA7BABE&gt;
 gpg: writing new key
@@ -123,34 +125,37 @@ sec  2048R/4CA7BABE  created: 2010-10-15  expires: never
                      card-no: F517 00000001
 ssb  2048R/084239CF  created: 2010-10-15  expires: never
 ssb  2048R/5BB065DC  created: 2010-10-22  expires: never
-(1)  NIIBE Yutaka &lt;gniibe@fsij.org&gt;</pre>
+(1)  NIIBE Yutaka &lt;gniibe@fsij.org&gt;
+</pre></div>
 </div>
 <p>The primary key is now on the Token and GnuPG says its card-no (F517 00000001),
 where F517 is the vendor ID of FSIJ.</p>
 <p>Secondly, I import my subkey of encryption.  I select key number &#8216;1&#8217;.</p>
-<div class="highlight-python"><pre>gpg&gt; key 1
+<div class="highlight-python"><div class="highlight"><pre>gpg&gt; key 1
 
 sec  2048R/4CA7BABE  created: 2010-10-15  expires: never
                      card-no: F517 00000001
 ssb* 2048R/084239CF  created: 2010-10-15  expires: never
 ssb  2048R/5BB065DC  created: 2010-10-22  expires: never
-(1)  NIIBE Yutaka &lt;gniibe@fsij.org&gt;</pre>
+(1)  NIIBE Yutaka &lt;gniibe@fsij.org&gt;
+</pre></div>
 </div>
 <p>You can see that the subkey is marked by &#8216;*&#8217;.
 I type <tt class="docutils literal"><span class="pre">keytocard</span></tt> command to import this subkey to Gnuk Token.
 I select <tt class="docutils literal"><span class="pre">2</span></tt> as it&#8217;s encryption key.</p>
-<div class="highlight-python"><pre>gpg&gt; keytocard
+<div class="highlight-python"><div class="highlight"><pre>gpg&gt; keytocard
 Signature key ....: [none]
 Encryption key....: [none]
 Authentication key: [none]
 
 Please select where to store the key:
    (2) Encryption key
-Your selection? 2</pre>
+Your selection? 2
+</pre></div>
 </div>
 <p>Then, GnuPG asks the passphrase of <strong>keys on PC</strong> again.  I enter.</p>
-<div class="highlight-python"><pre>You need a passphrase to unlock the secret key for
-user: "NIIBE Yutaka &lt;gniibe@fsij.org&gt;"
+<div class="highlight-python"><div class="highlight"><pre>You need a passphrase to unlock the secret key for
+user: &quot;NIIBE Yutaka &lt;gniibe@fsij.org&gt;&quot;
 2048-bit RSA key, ID 084239CF, created 2010-10-15
 &lt;PASSWORD-KEY-4CA7BABE&gt;
 gpg: writing new key
@@ -160,44 +165,48 @@ sec  2048R/4CA7BABE  created: 2010-10-15  expires: never
 ssb* 2048R/084239CF  created: 2010-10-15  expires: never
                      card-no: F517 00000001
 ssb  2048R/5BB065DC  created: 2010-10-22  expires: never
-(1)  NIIBE Yutaka &lt;gniibe@fsij.org&gt;</pre>
+(1)  NIIBE Yutaka &lt;gniibe@fsij.org&gt;
+</pre></div>
 </div>
 <p>The sub key is now on the Token and GnuPG says its card-no for it.</p>
 <p>I type <tt class="docutils literal"><span class="pre">key</span> <span class="pre">1</span></tt> to deselect key number &#8216;1&#8217;.</p>
-<div class="highlight-python"><pre>gpg&gt; key 1
+<div class="highlight-python"><div class="highlight"><pre>gpg&gt; key 1
 
 sec  2048R/4CA7BABE  created: 2010-10-15  expires: never
                      card-no: F517 00000001
 ssb  2048R/084239CF  created: 2010-10-15  expires: never
                      card-no: F517 00000001
 ssb  2048R/5BB065DC  created: 2010-10-22  expires: never
-(1)  NIIBE Yutaka &lt;gniibe@fsij.org&gt;</pre>
+(1)  NIIBE Yutaka &lt;gniibe@fsij.org&gt;
+</pre></div>
 </div>
 <p>Thirdly, I select sub key of authentication which has key number &#8216;2&#8217;.</p>
-<div class="highlight-python"><pre>gpg&gt; key 2
+<div class="highlight-python"><div class="highlight"><pre>gpg&gt; key 2
 
 sec  2048R/4CA7BABE  created: 2010-10-15  expires: never
                      card-no: F517 00000001
 ssb  2048R/084239CF  created: 2010-10-15  expires: never
                      card-no: F517 00000001
 ssb* 2048R/5BB065DC  created: 2010-10-22  expires: never
-(1)  NIIBE Yutaka &lt;gniibe@fsij.org&gt;</pre>
+(1)  NIIBE Yutaka &lt;gniibe@fsij.org&gt;
+</pre></div>
 </div>
 <p>You can see that the subkey number &#8216;2&#8217; is marked by &#8216;*&#8217;.
 I type <tt class="docutils literal"><span class="pre">keytocard</span></tt> command to import this subkey to Gnuk Token.
 I select <tt class="docutils literal"><span class="pre">3</span></tt> as it&#8217;s authentication key.</p>
-<div class="highlight-python"><pre>gpg&gt; keytocard
+<div class="highlight-python"><div class="highlight"><pre>gpg&gt; keytocard
 Signature key ....: [none]
 Encryption key....: [none]
 Authentication key: [none]
 
 Please select where to store the key:
    (3) Authentication key
-Your selection? 3</pre>
+Your selection? 3
+</pre></div>
 </div>
 <p>Then, GnuPG asks the passphrase of <strong>keys on PC</strong> again.  I enter.</p>
-<div class="highlight-python"><pre>You need a passphrase to unlock the secret key for
-user: "NIIBE Yutaka &lt;gniibe@fsij.org&gt;"
+<div class="highlight-python"><div class="highlight"><pre>You need a passphrase to unlock the secret key for
+user: &quot;NIIBE Yutaka &lt;gniibe@fsij.org&gt;&quot;
 2048-bit RSA key, ID 5BB065DC, created 2010-10-22
 &lt;PASSWORD-KEY-4CA7BABE&gt;
 gpg: writing new key
@@ -208,12 +217,14 @@ ssb  2048R/084239CF  created: 2010-10-15  expires: never
                      card-no: F517 00000001
 ssb* 2048R/5BB065DC  created: 2010-10-22  expires: never
                      card-no: F517 00000001
-(1)  NIIBE Yutaka &lt;gniibe@fsij.org&gt;</pre>
+(1)  NIIBE Yutaka &lt;gniibe@fsij.org&gt;
+</pre></div>
 </div>
 <p>The sub key is now on the Token and GnuPG says its card-no for it.</p>
 <p>Lastly, I save changes of <strong>keys on PC</strong> and quit GnuPG.</p>
-<div class="highlight-python"><pre>gpg&gt; save
-$</pre>
+<div class="highlight-python"><div class="highlight"><pre>gpg&gt; save
+$
+</pre></div>
 </div>
 <p>All secret keys are imported to Gnuk Token now.
 On PC, only references (card-no) to the Token remain
@@ -271,7 +282,7 @@ and secrets have been removed.</p>
     </div>
     <div class="footer">
         &copy; Copyright 2012, NIIBE Yutaka.
-      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.3.
     </div>
   </body>
 </html>
\ No newline at end of file
index 050245e..5899052 100644 (file)
@@ -1,5 +1,3 @@
-
-
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
@@ -15,7 +13,7 @@
     
     <script type="text/javascript">
       var DOCUMENTATION_OPTIONS = {
-        URL_ROOT:    '',
+        URL_ROOT:    './',
         VERSION:     '1.0',
         COLLAPSE_INDEX: false,
         FILE_SUFFIX: '.html',
@@ -73,7 +71,7 @@ same thing and it just refer user-password or admin-password.</p>
 <div class="section" id="set-up-pw1-pw3-and-reset-code">
 <h2>Set up PW1, PW3 and reset code<a class="headerlink" href="#set-up-pw1-pw3-and-reset-code" title="Permalink to this headline">¶</a></h2>
 <p>Invoke GnuPG with the option <tt class="docutils literal"><span class="pre">--card-edit</span></tt>.</p>
-<div class="highlight-python"><pre>$ gpg --card-edit
+<div class="highlight-python"><div class="highlight"><pre>$ gpg --card-edit
 Application ID ...: D276000124010200F517000000010000
 Version ..........: 2.0
 Manufacturer .....: FSIJ
@@ -103,7 +101,8 @@ ssb&gt;  2048R/084239CF  created: 2010-10-15  expires: never
 ssb&gt;  2048R/5BB065DC  created: 2010-10-22  expires: never
                       card-no: F517 00000001
 
-gpg/card&gt;</pre>
+gpg/card&gt;
+</pre></div>
 </div>
 <p>It shows the status of the card (as same as the output of <tt class="docutils literal"><span class="pre">gpg</span> <span class="pre">--card-status</span></tt>).</p>
 <p>Then, GnuPG enters its own command interaction mode.  The prompt is <tt class="docutils literal"><span class="pre">gpg/card&gt;</span></tt>.</p>
@@ -113,7 +112,7 @@ Note that, by only changing user&#8217;s PIN, it enables &#8220;admin less mode&
 That is, PW1 = PW3.
 Note that <em>the length of PIN should be more than (or equals to) 8</em> for
 &#8220;admin less mode&#8221;.</p>
-<div class="highlight-python"><pre>gpg/card&gt; passwd
+<div class="highlight-python"><div class="highlight"><pre>gpg/card&gt; passwd
 gpg: OpenPGP card no. D276000124010200F517000000010000 detected
 
 Please enter the PIN
@@ -124,7 +123,8 @@ Enter New PIN: &lt;PASSWORD-OF-GNUK&gt;
 
 New PIN
 Repeat this PIN: &lt;PASSWORD-OF-GNUK&gt;
-PIN changed.</pre>
+PIN changed.
+</pre></div>
 </div>
 <p>The &#8220;admin less mode&#8221; is Gnuk only feature, not defined in the
 OpenPGPcard specification.  By using &#8220;admin less mode&#8221;, it will be
@@ -138,7 +138,7 @@ with regards to PW1 and PW3.)</p>
 <p>Lastly, I setup reset code, entering admin mode.
 Having reset code, you can unblock PIN when the token will be blocked
 (by wrong attempt to entering PIN).  This is optional step.</p>
-<div class="highlight-python"><pre>gpg/card&gt; admin
+<div class="highlight-python"><div class="highlight"><pre>gpg/card&gt; admin
 Admin commands are allowed
 
 gpg/card&gt; passwd
@@ -169,7 +169,8 @@ Reset Code set.
 4 - set the Reset Code
 Q - quit
 
-Your selection? q</pre>
+Your selection? q
+</pre></div>
 </div>
 <p>Then, I quit.</p>
 <div class="highlight-python"><div class="highlight"><pre><span class="n">gpg</span><span class="o">/</span><span class="n">card</span><span class="o">&gt;</span> <span class="n">quit</span>
@@ -239,7 +240,7 @@ Your selection? q</pre>
     </div>
     <div class="footer">
         &copy; Copyright 2012, NIIBE Yutaka.
-      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.3.
     </div>
   </body>
 </html>
\ No newline at end of file
index b27f960..c9d6c1c 100644 (file)
@@ -1,5 +1,3 @@
-
-
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
@@ -15,7 +13,7 @@
     
     <script type="text/javascript">
       var DOCUMENTATION_OPTIONS = {
-        URL_ROOT:    '',
+        URL_ROOT:    './',
         VERSION:     '1.0',
         COLLAPSE_INDEX: false,
         FILE_SUFFIX: '.html',
@@ -57,7 +55,7 @@
 <div class="section" id="personalize-your-gnuk-token">
 <h2>Personalize your Gnuk Token<a class="headerlink" href="#personalize-your-gnuk-token" title="Permalink to this headline">¶</a></h2>
 <p>Invoke GnuPG with the option <tt class="docutils literal"><span class="pre">--card-edit</span></tt>.</p>
-<div class="highlight-python"><pre>$ gpg --card-edit
+<div class="highlight-python"><div class="highlight"><pre>$ gpg --card-edit
 Application ID ...: D276000124010200FFFE330069060000
 Version ..........: 2.0
 Manufacturer .....: unmanaged S/N range
@@ -77,26 +75,28 @@ Encryption key....: [none]
 Authentication key: [none]
 General key info..: [none]
 
-gpg/card&gt;</pre>
+gpg/card&gt;
+</pre></div>
 </div>
 <p>It shows the status of the card (as same as the output of <tt class="docutils literal"><span class="pre">gpg</span> <span class="pre">--card-status</span></tt>).</p>
 <p>Then, GnuPG enters its own command interaction mode.  The prompt is <tt class="docutils literal"><span class="pre">gpg/card&gt;</span></tt>.</p>
 <p>First, enabling admin command, I put name of mine.
 Note that I input admin PIN of factory setting (12345678) here.</p>
-<div class="highlight-python"><pre>gpg/card&gt; admin
+<div class="highlight-python"><div class="highlight"><pre>gpg/card&gt; admin
 Admin commands are allowed
 
 gpg/card&gt; name
-Cardholder's surname: Niibe
-Cardholder's given name: Yutaka
+Cardholder&#39;s surname: Niibe
+Cardholder&#39;s given name: Yutaka
 gpg: 3 Admin PIN attempts remaining before card is permanently locked
 
 Please enter the Admin PIN
-Enter Admin PIN: 12345678</pre>
+Enter Admin PIN: 12345678
+</pre></div>
 </div>
 <p>Secondly, I put some other informations, such as language, sex,
 login, and URL.  URL specifies the place where I put my public keys.</p>
-<div class="highlight-python"><pre>gpg/card&gt; lang
+<div class="highlight-python"><div class="highlight"><pre>gpg/card&gt; lang
 Language preferences: ja
 
 gpg/card&gt; sex
@@ -106,7 +106,8 @@ gpg/card&gt; url
 URL to retrieve public key: http://www.gniibe.org/gniibe.asc
 
 gpg/card&gt; login
-Login data (account name): gniibe</pre>
+Login data (account name): gniibe
+</pre></div>
 </div>
 <p>Since I don&#8217;t force PIN input everytime,
 toggle it to non-force-pin-for-signature.</p>
@@ -180,7 +181,7 @@ toggle it to non-force-pin-for-signature.</p>
     </div>
     <div class="footer">
         &copy; Copyright 2012, NIIBE Yutaka.
-      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.3.
     </div>
   </body>
 </html>
\ No newline at end of file
index a94de63..0d0ff92 100644 (file)
@@ -1,5 +1,3 @@
-
-
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
@@ -15,7 +13,7 @@
     
     <script type="text/javascript">
       var DOCUMENTATION_OPTIONS = {
-        URL_ROOT:    '',
+        URL_ROOT:    './',
         VERSION:     '1.0',
         COLLAPSE_INDEX: false,
         FILE_SUFFIX: '.html',
@@ -65,19 +63,21 @@ as it comes with its default serial number based on MCU&#8217;s chip ID.</p>
 <div class="section" id="preparation">
 <h2>Preparation<a class="headerlink" href="#preparation" title="Permalink to this headline">¶</a></h2>
 <p>Make sure there is no <tt class="docutils literal"><span class="pre">scdaemon</span></tt> for configuring Gnuk Token.  You can  kill <tt class="docutils literal"><span class="pre">scdaemon</span></tt> by:</p>
-<div class="highlight-python"><pre>$ gpg-connect-agent "SCD KILLSCD" "SCD BYE" /bye</pre>
+<div class="highlight-python"><div class="highlight"><pre>$ gpg-connect-agent &quot;SCD KILLSCD&quot; &quot;SCD BYE&quot; /bye
+</pre></div>
 </div>
 </div>
 <div class="section" id="serial-number-optional">
 <h2>Serial Number (optional)<a class="headerlink" href="#serial-number-optional" title="Permalink to this headline">¶</a></h2>
 <p>In the file <tt class="docutils literal"><span class="pre">GNUK_SERIAL_NUMBER</span></tt>, each line has email and 6-byte serial number.  The first two bytes are organization number (F5:17 is for FSIJ).  Last four bytes are number for tokens.</p>
 <p>The tool <tt class="docutils literal"><span class="pre">../tool/gnuk_put_binary_libusb.py</span></tt> examines  environment variable of <tt class="docutils literal"><span class="pre">EMAIL</span></tt>, and writes corresponding serial number to Gnuk Token.</p>
-<div class="highlight-python"><pre>$ ../tool/gnuk_put_binary_libusb.py -s ../GNUK_SERIAL_NUMBER
+<div class="highlight-python"><div class="highlight"><pre>$ ../tool/gnuk_put_binary_libusb.py -s ../GNUK_SERIAL_NUMBER
 Writing serial number
 Device:  006
 Configuration:  1
 Interface:  0
-d2 76 00 01 24 01 02 00 f5 17 00 00 00 01 00 00</pre>
+d2 76 00 01 24 01 02 00 f5 17 00 00 00 01 00 00
+</pre></div>
 </div>
 <p>The example above is the case of libusb version.</p>
 <p>Use the tool <tt class="docutils literal"><span class="pre">../tool/gnuk_put_binary.py</span></tt> instead , for PC/SC Lite.
@@ -146,7 +146,7 @@ You need PyScard for this.</p>
     </div>
     <div class="footer">
         &copy; Copyright 2012, NIIBE Yutaka.
-      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.3.
     </div>
   </body>
 </html>
\ No newline at end of file
index 435f68c..6485124 100644 (file)
@@ -1,5 +1,3 @@
-
-
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
@@ -15,7 +13,7 @@
     
     <script type="text/javascript">
       var DOCUMENTATION_OPTIONS = {
-        URL_ROOT:    '',
+        URL_ROOT:    './',
         VERSION:     '1.0',
         COLLAPSE_INDEX: false,
         FILE_SUFFIX: '.html',
@@ -27,8 +25,8 @@
     <script type="text/javascript" src="_static/doctools.js"></script>
     <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
     <link rel="top" title="Gnuk Documentation 1.0 documentation" href="index.html" />
-    <link rel="next" title="GnuPG settings for GNOME 3" href="gnome3-gpg-settings.html" />
-    <link rel="prev" title="Using Gnuk Token with another computer" href="using-gnuk-token-with-another-computer.html" /> 
+    <link rel="next" title="Stopping/Resetting SCDAEMON" href="stop-scdaemon.html" />
+    <link rel="prev" title="Introduction" href="intro.html" /> 
   </head>
   <body>
     <div class="related">
           <a href="genindex.html" title="General Index"
              accesskey="I">index</a></li>
         <li class="right" >
-          <a href="gnome3-gpg-settings.html" title="GnuPG settings for GNOME 3"
+          <a href="stop-scdaemon.html" title="Stopping/Resetting SCDAEMON"
              accesskey="N">next</a> |</li>
         <li class="right" >
-          <a href="using-gnuk-token-with-another-computer.html" title="Using Gnuk Token with another computer"
+          <a href="intro.html" title="Introduction"
              accesskey="P">previous</a> |</li>
         <li><a href="index.html">Gnuk Documentation 1.0 documentation</a> &raquo;</li> 
       </ul>
 <div class="section" id="gnupg-gpg-conf">
 <h2>.gnupg/gpg.conf<a class="headerlink" href="#gnupg-gpg-conf" title="Permalink to this headline">¶</a></h2>
 <p>I create <tt class="docutils literal"><span class="pre">.gnupg/gpg.conf</span></tt> file with the following content.</p>
-<div class="highlight-python"><pre>use-agent
+<div class="highlight-python"><div class="highlight"><pre>use-agent
 personal-digest-preferences SHA256
 cert-digest-algo SHA256
 default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
 
-default-key 0x4ca7babe</pre>
+default-key 0x4ca7babe
+</pre></div>
 </div>
 <p>In addition to the <tt class="docutils literal"><span class="pre">use-agent</span></tt> option, set preferences on algorithms, and specify my default key.</p>
 <p>The <tt class="docutils literal"><span class="pre">use-agent</span></tt> option is for GnuPG 1.4.x and it means using gpg-agent if available.
@@ -73,8 +72,9 @@ If no option, GnuPG 1.4.x directly connects to Gnuk Token by itself, instead of
 </div>
 <div class="section" id="let-gpg-agent-manage-ssh-key">
 <h2>Let gpg-agent manage SSH key<a class="headerlink" href="#let-gpg-agent-manage-ssh-key" title="Permalink to this headline">¶</a></h2>
-<p>I deactivate seahose-agent.  Also, for GNOME 2, I deactivate gnome-keyring managing SSH key.</p>
-<div class="highlight-python"><pre>$ gconftool-2 --type bool --set /apps/gnome-keyring/daemon-components/ssh false</pre>
+<p>I deactivate seahorse-agent.  Also, for GNOME 2, I deactivate gnome-keyring managing SSH key.</p>
+<div class="highlight-python"><div class="highlight"><pre>$ gconftool-2 --type bool --set /apps/gnome-keyring/daemon-components/ssh false
+</pre></div>
 </div>
 <p>I edit the file /etc/X11/Xsession.options and comment out use-ssh-agent line.</p>
 <p>Then, I create <tt class="docutils literal"><span class="pre">.gnupg/gpg-agent.conf</span></tt> file with the following content.</p>
@@ -108,11 +108,11 @@ If no option, GnuPG 1.4.x directly connects to Gnuk Token by itself, instead of
 </ul>
 
   <h4>Previous topic</h4>
-  <p class="topless"><a href="using-gnuk-token-with-another-computer.html"
-                        title="previous chapter">Using Gnuk Token with another computer</a></p>
+  <p class="topless"><a href="intro.html"
+                        title="previous chapter">Introduction</a></p>
   <h4>Next topic</h4>
-  <p class="topless"><a href="gnome3-gpg-settings.html"
-                        title="next chapter">GnuPG settings for GNOME 3</a></p>
+  <p class="topless"><a href="stop-scdaemon.html"
+                        title="next chapter">Stopping/Resetting SCDAEMON</a></p>
   <h3>This Page</h3>
   <ul class="this-page-menu">
     <li><a href="_sources/gpg-settings.txt"
@@ -142,17 +142,17 @@ If no option, GnuPG 1.4.x directly connects to Gnuk Token by itself, instead of
           <a href="genindex.html" title="General Index"
              >index</a></li>
         <li class="right" >
-          <a href="gnome3-gpg-settings.html" title="GnuPG settings for GNOME 3"
+          <a href="stop-scdaemon.html" title="Stopping/Resetting SCDAEMON"
              >next</a> |</li>
         <li class="right" >
-          <a href="using-gnuk-token-with-another-computer.html" title="Using Gnuk Token with another computer"
+          <a href="intro.html" title="Introduction"
              >previous</a> |</li>
         <li><a href="index.html">Gnuk Documentation 1.0 documentation</a> &raquo;</li> 
       </ul>
     </div>
     <div class="footer">
         &copy; Copyright 2012, NIIBE Yutaka.
-      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.3.
     </div>
   </body>
 </html>
\ No newline at end of file
index 0284c17..7079ffb 100644 (file)
@@ -1,5 +1,3 @@
-
-
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
@@ -15,7 +13,7 @@
     
     <script type="text/javascript">
       var DOCUMENTATION_OPTIONS = {
-        URL_ROOT:    '',
+        URL_ROOT:    './',
         VERSION:     '1.0',
         COLLAPSE_INDEX: false,
         FILE_SUFFIX: '.html',
 <li class="toctree-l2"><a class="reference internal" href="using-gnuk-token-with-another-computer.html#update-trustdb-for-the-key-on-gnuk-token">Update trustdb for the key on Gnuk Token</a></li>
 </ul>
 </li>
-<li class="toctree-l1"><a class="reference internal" href="gnome3-gpg-settings.html">GnuPG settings for GNOME 3</a><ul>
-<li class="toctree-l2"><a class="reference internal" href="gnome3-gpg-settings.html#gnome-keyrings-in-gnome-3">GNOME keyrings in GNOME 3</a></li>
-<li class="toctree-l2"><a class="reference internal" href="gnome3-gpg-settings.html#gnome-session-properties">GNOME-SESSION-PROPERTIES</a></li>
+<li class="toctree-l1"><a class="reference internal" href="gnome3-gpg-settings.html">GnuPG settings for GNOME 3.1x and GNOME 3.0</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="gnome3-gpg-settings.html#gnome-keyrings-in-gnome-3-1x">GNOME keyrings in GNOME 3.1x</a></li>
+<li class="toctree-l2"><a class="reference internal" href="gnome3-gpg-settings.html#gnome-keyrings-in-gnome-3-0-by-gnome-session-properties">GNOME keyrings in GNOME 3.0 by GNOME-SESSION-PROPERTIES</a></li>
 </ul>
 </li>
 <li class="toctree-l1"><a class="reference internal" href="development.html">Development Environment</a><ul>
         <div class="sphinxsidebarwrapper">
   <h3><a href="#">Table Of Contents</a></h3>
   <ul>
-<li><a class="reference internal" href="#">Gnuk Documentation</a><ul>
-</ul>
-</li>
+<li><a class="reference internal" href="#">Gnuk Documentation</a></li>
 <li><a class="reference internal" href="#indices-and-tables">Indices and tables</a></li>
 </ul>
 
     </div>
     <div class="footer">
         &copy; Copyright 2012, NIIBE Yutaka.
-      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.3.
     </div>
   </body>
 </html>
\ No newline at end of file
index 018e16b..a9a8781 100644 (file)
@@ -1,5 +1,3 @@
-
-
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
@@ -15,7 +13,7 @@
     
     <script type="text/javascript">
       var DOCUMENTATION_OPTIONS = {
-        URL_ROOT:    '',
+        URL_ROOT:    './',
         VERSION:     '1.0',
         COLLAPSE_INDEX: false,
         FILE_SUFFIX: '.html',
@@ -168,7 +166,7 @@ In version 1.1.x, Gnuk supports following boards.</p>
     </div>
     <div class="footer">
         &copy; Copyright 2012, NIIBE Yutaka.
-      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.3.
     </div>
   </body>
 </html>
\ No newline at end of file
diff --git a/doc-gnuk/objects.inv b/doc-gnuk/objects.inv
new file mode 100644 (file)
index 0000000..778d427
Binary files /dev/null and b/doc-gnuk/objects.inv differ
index 0b3d248..c670d2a 100644 (file)
@@ -1,5 +1,3 @@
-
-
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
@@ -15,7 +13,7 @@
     
     <script type="text/javascript">
       var DOCUMENTATION_OPTIONS = {
-        URL_ROOT:    '',
+        URL_ROOT:    './',
         VERSION:     '1.0',
         COLLAPSE_INDEX: false,
         FILE_SUFFIX: '.html',
@@ -31,6 +29,8 @@
   <script type="text/javascript">
     jQuery(function() { Search.loadIndex("searchindex.js"); });
   </script>
+  
+  <script type="text/javascript" id="searchindexloader"></script>
    
 
   </head>
@@ -94,7 +94,7 @@
     </div>
     <div class="footer">
         &copy; Copyright 2012, NIIBE Yutaka.
-      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.3.
     </div>
   </body>
 </html>
\ No newline at end of file
diff --git a/doc-gnuk/searchindex.js b/doc-gnuk/searchindex.js
new file mode 100644 (file)
index 0000000..92556fe
--- /dev/null
@@ -0,0 +1 @@
+Search.setIndex({envversion:42,terms:{all:[11,13,10,3,8],entropi:8,rom:0,scd:[1,12],d276000124010200f517000000010000:[7,10],consum:8,month:8,four:1,secondli:[11,3],unblock:10,follow:[6,9,3],disk:8,openpgp:[6,9,10],forget:8,udevadm:2,decid:7,flash:0,"79a7":[7,10],send:8,program:[5,7,10],decis:7,autostart:5,under:0,sha256:6,deactiv:6,digit:10,sourc:7,risk:8,fals:6,account:11,mous:8,"62af":[7,10,8],veri:8,retriev:11,openpgpcard:10,elgam:8,button:5,list:[6,7],factori:[11,10,3],unmanag:11,"9c33":[7,10],gnuk_serial_numb:1,setup:[1,10],dir:3,pleas:[0,2,3,5,7,8,10,11,13],stm8:9,omment:8,sigl:10,sign:[9,8],everytim:11,zero:9,run:[0,4,6],index:4,what:[4,8],sub:[12,7,3,8],"4ca7":[7,10,8],section:[0,5,8],invok:[3,5,7,8,11,10],current:8,version:[0,1,7,9,11,10],"084239cf":[7,10,3,8],net:[0,8],full:10,never:[7,10,3,8],here:[0,3,6,8,11,13],free:[7,9,3,8],debugg:[0,2],address:8,becom:10,modifi:8,sinc:11,search:4,male:[7,10],technolog:8,cert:6,permit:[7,3,8],action:[2,8],chang:[0,2,3,7,8,10,13],chanc:8,firefox:9,although:3,vid:0,app:6,foundat:[7,3,8],readili:0,ask:[3,8],unix:5,instal:2,keysiz:8,memor:10,select:[10,3,8],highli:0,from:[0,8],describ:[7,13,3,8],niib:[11,7,10,3,8],memori:8,pref:[11,7,10],upgrad:0,privet:8,next:7,passport:7,recommend:[0,6,10,8],type:[0,3,6,7,8,12],until:8,toggl:[11,3,8],more:[12,7,10,8],babe:[7,10,8],"2048r":[11,7,10,3,8],relat:7,line:[1,6,2,5],stone:9,warn:8,examin:[1,7],nomal:8,fly:9,none:[0,7,11,3],word:10,der:8,work:[10,8],remain:[11,10,3],can:[0,1,3,5,7,8,9,10,12],learn:4,purpos:[0,12],fetch:4,control:[9,2],prompt:[11,7,10,3,8],tab:5,give:[2,8],process:7,lock:[11,10,3],chip:1,agent:[1,8,5],want:[7,10,3,8],yutaka:[11,7,10,3,8],serial:[11,10],string:10,alwai:[6,8],gcc:0,multipl:3,"4ca7bab":[7,10,3,8],secur:8,newlib:0,write:[1,3],how:[4,3,5,6,8,13],env:2,answer:3,instead:[1,6],duesseldorf:8,updat:[4,8],product:0,resourc:8,max:[11,7,10],"5bb0":[7,10],aes256:6,befor:[11,13,10,3],wrong:10,mai:8,law:[7,3,8],data:[11,7,10],util:[12,8],attempt:[11,10,3],practic:12,counter:[11,7,10],correspond:1,imposs:0,issu:[2,8],inform:11,"4e6f":[7,10],allow:[11,10,8],enter:[11,10,3,8],order:2,talk:12,bitsiz:8,move:[3,8],becaus:[0,12,8],through:[6,9],keyboard:8,still:[0,13],digest:6,idvendor:2,group:2,dichter:8,gnuk_put_binari:1,gen:8,better:8,requir:[9,8],creat:[6,7,10,3,8],mail:8,main:[7,8],easier:10,wouldn:8,non:11,good:[0,5,7,8],"return":7,thei:3,handl:[12,2],dai:[5,8],initi:8,nation:8,"7a0a":[7,10,8],fingerprint:[7,8],now:[7,13,3,8],introduct:4,term:10,name:[11,12,7,10,8],edit:[3,5,6,7,8,10,11],authent:[3,7,8,9,11,10],separ:9,micro:9,token:[5,8],alreadi:2,mode:[11,10,3,2],each:1,x11:6,complet:8,mean:[0,6,10],compil:0,harm:6,"5ebd":[7,10,8],individu:10,idea:[9,8],realli:[7,3,8],unlock:[3,8],connect:[1,6,12,4],year:8,our:[5,8],extract:[0,9],special:8,out:[0,6],variabl:1,shown:7,space:11,armor:8,content:[4,6],id_smartcard_read:2,correct:[7,8],dsa:8,after:[13,3,8],given:11,pub:[7,10,3,8],standard:8,asc:[11,7,10,8],base:[0,1],put:[13,7,11,3],org:[11,7,10,3,8],"byte":[1,8],card:[11,10,7,9,3],care:[12,3],openssh:[6,9],recov:8,thing:[5,10,3,8],"0x4ca7bab":6,place:[11,2],nist:8,unknown:7,think:5,first:[11,1,10,8],softwar:[7,9,3,8],rang:11,directli:[6,12],smartcard:12,onc:[1,8],independ:[9,10],number:[11,10,3,8],scute:9,gconftool:6,keyimport:3,done:8,pgp:8,primari:[3,8],size:8,redistribut:[7,3,8],differ:[13,7,10,3,8],dfu:0,gnuk_put_binary_libusb:1,interact:[11,10,3],gpg:[1,3,5,8,11,10,13],sometim:10,construct:8,necessarili:7,too:[7,8],privaci:9,store:[9,3],option:[0,11,10,8],tool:[0,1,5],copi:3,specifi:[0,2,6,7,8,11],part:9,nobodi:9,than:[10,2],wide:8,kind:8,target:[0,4],sha224:6,remov:[5,3],charact:10,project:0,gnupg:8,consumpt:8,other:[11,7,10,8],sai:[7,3],comput:[4,9,8],beforehand:3,mine:11,onlyshowin:5,packag:2,expir:[7,10,3,8],have:[0,2,3,5,6,8,10,12],need:[0,1,2,3,6,7,8,12],jtag:[0,2],lib:2,arm:0,note:[0,2,3,7,8,10,11,13],also:6,ideal:12,exampl:[1,10,8],take:8,which:[12,7,10,3,8],singl:8,sure:1,unless:7,normal:10,passwd:10,kai:8,"234b":[0,2],keyserv:8,mate:5,model:8,trustdb:[4,8],don:[1,12,7,11,13],expert:8,url:[11,7,10],later:[0,2],request:[7,8],doe:8,anoth:[4,10,3,8],libusb:[1,9,4],"65dc":[7,10],show:[11,10],tri:6,random:8,bring:7,session:8,radio:5,permiss:2,identifi:8,discoveri:9,anywai:6,access:6,onli:[1,2,3,7,8,9,10,13],exactli:12,gniib:[11,7,10,3,8],launchpad:0,copyright:[7,3,8],menu:7,explain:10,configur:[0,5],behind:12,should:[0,12,10,8],manufactur:[11,7,10],experiment:0,tape:2,idproduct:2,factor:8,defin:10,xdg:5,"4e70":[7,10],invokd:8,stop:4,ssh:[5,8],"new":[6,10,3],report:2,killscd:[1,12],restart:7,ssb:[7,10,3],prime:8,enabl:[0,11,6,10,3],organ:1,reload:2,common:8,contain:7,where:[12,9,11,3],wrote:5,user:[2,3,5,7,8,10],certif:[9,8],set:8,signatur:[11,7,10,3,8],startup:5,sex:[11,7,10],see:[0,13,7,9,3],sec:[7,10,3],gnupg_rules_end:2,aes192:6,emal:11,page:4,statu:[11,7,10],detect:10,correctli:7,someth:[5,3,2],e805:[7,10],label:2,state:7,won:7,between:8,"import":8,email:[1,8],attribut:[11,7,10],verifi:7,pcscd:9,entir:8,extent:[7,3,8],solv:8,come:1,problem:8,addit:6,protect:[0,8],last:[1,13],admin:[11,10,3],howev:[7,8],equal:10,etc:[5,6,7,2,8],mani:8,login:[11,7,10],comment:[6,8],elf:0,linux:1,trust:[7,3,8],assum:[1,3],orig:2,quit:[11,13,7,10,3],ultim:[7,3,8],surnam:11,pyscard:1,devic:[0,1,8,9,4],gnupg2:2,been:[3,8],mark:[3,8],compon:6,secret:[0,3,7,8,9,13],besid:10,"00b4":[7,10,8],basic:0,tini:[0,9],pid:0,b4d9:[7,10],"20a0":2,ani:12,deliber:8,mcu:1,correspoind:7,vidpid:0,"case":[1,12,10,3,2],bye:[1,12],look:7,servic:5,zlib:6,d276000124010200fffe330069060000:11,"while":7,b6ba:[7,10],abov:[1,10,8],margin:[7,8],would:[0,8],helper:10,swd:[0,2],"24bd":[7,10,8],readm:0,them:9,itself:6,revis:8,ascii:8,uniti:5,perform:8,make:[0,1,8],same:[11,10,3,8],binari:8,lite:[1,9,2],document:[13,3],conflict:6,difficult:8,week:8,finish:8,http:[0,11,7,10],kit:9,capabl:8,two:[1,10,3,8],encrypt:[11,7,10,3,8],pinentri:10,implement:[0,9],older:2,firstli:[10,3],thu:8,well:0,"1f30":[7,10],person:[10,3],without:13,command:[11,12,10,3,8],thi:[1,2,3,5,6,7,8,10,12,13],everyth:12,paperkei:8,stbee:9,usual:[0,2],protocol:9,just:[5,7,10,8],less:[10,8],olimex:[0,9],kill:1,passphras:[3,8],yet:7,languag:[11,7,10],f517:[7,10,3],web:[9,8],easi:5,interfer:5,had:8,desktop:[5,2],identif:10,add:[7,2],"3b48":[7,10,8],board:[0,4],input:[11,10,8],save:[13,3,8],modul:4,real:8,applic:[11,7,10],vendor:[0,3],advis:8,read:0,prefer:[11,6,10,8],fsij:[0,1,2,3,7,8,10],know:7,password:[5,10,3,8],daemon:[6,12,2],like:[5,3,2],specif:10,server:[7,8],collect:8,dc79:[7,10],output:[11,10,8],manag:8,www:[11,7,10],right:5,old:5,some:[11,12,10,8],somehow:0,udev:4,unspecifi:11,"export":[3,8],proper:5,cardhold:[11,7,10],tmp:3,deselect:[3,8],total:7,confirm:[12,3,8],retri:[11,7,10],exit:12,"42e1":[7,10],three:8,refer:[10,3],encourag:10,forcesig:11,power:8,uncompress:6,sha384:6,usag:[4,3,8],symlink:2,viabl:8,stm32:9,step:[1,10,13],prerequisit:4,found:7,stlinkv2:0,usb:[0,9,2],src:0,about:12,usa:8,scdaemon:[1,6,4],constraint:8,resetcod:10,commun:4,stlink:2,algo:6,disabl:[0,5],block:10,subsystem:2,client:9,own:[11,10,3,2,8],lastli:[13,10,3],automat:[12,2],c42d:[7,10],warranti:[7,3,8],guard:9,storag:8,your:[0,3,8],thirdli:3,processor:9,institut:8,log:[13,3],wai:[10,3,8],addkei:8,transfer:8,support:[0,2,6,8,9,12],"long":8,custom:5,avail:[6,7,13,3,8],interfac:1,includ:10,lot:8,subkei:[3,8],sha512:6,"function":9,zip:6,h103:9,form:8,enough:8,forc:[11,7,10],regard:10,back:[7,8],perman:[11,10,3],link:[0,4],gain:8,newer:2,cryptograph:4,"true":8,bug:[12,2],heinrich:8,info:[11,7,10],xsession:6,attr:2,possibl:[0,8],"default":[1,6,8],f5f7:[7,10],"39cf":[7,10],displai:8,below:8,"5bb065dc":[7,10,3,8],dfuse:0,keytocard:[13,3],embed:0,featur:[0,4,10],uid:8,pin:[11,7,10,3],dure:8,decrypt:9,seahors:6,jessi:2,uit:8,file:[1,6,8,2,5],check:[5,7,8],inc:[7,3,8],again:3,bzip2:6,"26f2":[7,10],when:[6,7,10,2,8],cast5:6,valid:[7,3,8],bool:6,eabi:0,peopl:[10,8],test:3,you:[0,1,2,3,7,8,10,12],stm32f103:9,repeat:10,firmwar:0,fulli:7,consid:[0,8],libccid:9,debian:[7,2],pool:8,lang:11,hein:8,heinrichh:8,longer:[10,8],algorithm:[6,8],directori:[0,7,3,8],"04e6":2,id_smartcard_reader_driv:2,rule:4,"42f1":[7,10,8],fst:9,time:[7,8],far:7,decemb:0},objtypes:{},objnames:{},filenames:["development","gnuk-token-initial-configuration","udev-rules","gnuk-keytocard","index","gnome3-gpg-settings","gpg-settings","using-gnuk-token-with-another-computer","generating-2048-RSA-key","intro","gnuk-passphrase-setting","gnuk-personalization","stop-scdaemon","gnuk-keytocard-noremoval"],titles:["Development Environment","Initial Configuration of Gnuk Token","Device Configuration for Gnuk Token with libusb","Key import from PC to Gnuk Token","Gnuk Documentation","GnuPG settings for GNOME 3.1x and GNOME 3.0","GnuPG settings","Using Gnuk Token with another computer","Generating 2048-bit RSA keys","Introduction","Set up your passphrase for your Gnuk Token","Personalization of Gnuk Token","Stopping/Resetting SCDAEMON","Key import from PC to Gnuk Token (no removal)"],objects:{},titleterms:{code:10,comput:7,pw3:10,pw1:10,number:1,terminolog:10,set:[5,6,10],connect:7,conf:6,tabl:4,passphras:10,featur:9,your:[11,10],what:9,develop:[0,9],prepar:1,commun:12,anoth:7,gpg:[6,12],devic:2,length:8,publish:8,configur:[1,2],build:0,indic:4,hardwar:0,"import":[13,3],bit:8,document:4,target:9,"public":[7,8],refer:6,gnuk:[0,1,2,3,4,7,9,10,11,13],run:9,option:1,kei:[6,7,13,3,8],keyr:5,gener:8,stop:12,privat:8,initi:1,rsa:8,how:12,host:[9,8],libusb:2,let:[6,12],udev:2,prerequisit:9,condit:1,from:[13,3],cryptograph:9,serial:1,trustdb:7,reset:[12,10],openocd:0,usag:9,gnome:5,scdaemon:12,gnu:0,toolchain:0,remov:13,properti:5,board:9,rule:2,manag:6,person:11,token:[1,2,3,7,9,10,11,13],session:5,environ:[0,9],gnupg:[5,6],agent:[6,12],learn:12,link:2,introduct:9,updat:7,backup:8,fetch:7,ssh:6}})
\ No newline at end of file
index 9f78582..ae5e8e4 100644 (file)
@@ -1,5 +1,3 @@
-
-
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
@@ -15,7 +13,7 @@
     
     <script type="text/javascript">
       var DOCUMENTATION_OPTIONS = {
-        URL_ROOT:    '',
+        URL_ROOT:    './',
         VERSION:     '1.0',
         COLLAPSE_INDEX: false,
         FILE_SUFFIX: '.html',
@@ -28,7 +26,7 @@
     <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
     <link rel="top" title="Gnuk Documentation 1.0 documentation" href="index.html" />
     <link rel="next" title="Device Configuration for Gnuk Token with libusb" href="udev-rules.html" />
-    <link rel="prev" title="Introduction" href="intro.html" /> 
+    <link rel="prev" title="GnuPG settings" href="gpg-settings.html" /> 
   </head>
   <body>
     <div class="related">
@@ -41,7 +39,7 @@
           <a href="udev-rules.html" title="Device Configuration for Gnuk Token with libusb"
              accesskey="N">next</a> |</li>
         <li class="right" >
-          <a href="intro.html" title="Introduction"
+          <a href="gpg-settings.html" title="GnuPG settings"
              accesskey="P">previous</a> |</li>
         <li><a href="index.html">Gnuk Documentation 1.0 documentation</a> &raquo;</li> 
       </ul>
@@ -68,7 +66,8 @@ as it supports sub-command &#8220;SCD&#8221;, exactly for this purpose.</p>
 <div class="section" id="stopping-scdaemon">
 <h2>Stopping SCDAEMON<a class="headerlink" href="#stopping-scdaemon" title="Permalink to this headline">¶</a></h2>
 <p>To stop SCDAEMON and let it exit, type:</p>
-<div class="highlight-python"><pre>$ gpg-connect-agent "SCD KILLSCD" "SCD BYE" /bye</pre>
+<div class="highlight-python"><div class="highlight"><pre>$ gpg-connect-agent &quot;SCD KILLSCD&quot; &quot;SCD BYE&quot; /bye
+</pre></div>
 </div>
 <p>Then, you can confirm that there is no SCDAEMON any more by <tt class="docutils literal"><span class="pre">ps</span></tt>
 command.</p>
@@ -76,7 +75,8 @@ command.</p>
 <div class="section" id="let-gpg-agent-scdaemon-learn">
 <h2>Let GPG-AGENT/SCDAEMON learn<a class="headerlink" href="#let-gpg-agent-scdaemon-learn" title="Permalink to this headline">¶</a></h2>
 <p>To let gpg-agent/scdaemon learn from Gnuk Token, type:</p>
-<div class="highlight-python"><pre>$ gpg-connect-agent learn /bye</pre>
+<div class="highlight-python"><div class="highlight"><pre>$ gpg-connect-agent learn /bye
+</pre></div>
 </div>
 </div>
 </div>
@@ -98,8 +98,8 @@ command.</p>
 </ul>
 
   <h4>Previous topic</h4>
-  <p class="topless"><a href="intro.html"
-                        title="previous chapter">Introduction</a></p>
+  <p class="topless"><a href="gpg-settings.html"
+                        title="previous chapter">GnuPG settings</a></p>
   <h4>Next topic</h4>
   <p class="topless"><a href="udev-rules.html"
                         title="next chapter">Device Configuration for Gnuk Token with libusb</a></p>
@@ -135,14 +135,14 @@ command.</p>
           <a href="udev-rules.html" title="Device Configuration for Gnuk Token with libusb"
              >next</a> |</li>
         <li class="right" >
-          <a href="intro.html" title="Introduction"
+          <a href="gpg-settings.html" title="GnuPG settings"
              >previous</a> |</li>
         <li><a href="index.html">Gnuk Documentation 1.0 documentation</a> &raquo;</li> 
       </ul>
     </div>
     <div class="footer">
         &copy; Copyright 2012, NIIBE Yutaka.
-      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.3.
     </div>
   </body>
 </html>
\ No newline at end of file
index db6dbde..3f17011 100644 (file)
@@ -1,5 +1,3 @@
-
-
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
@@ -15,7 +13,7 @@
     
     <script type="text/javascript">
       var DOCUMENTATION_OPTIONS = {
-        URL_ROOT:    '',
+        URL_ROOT:    './',
         VERSION:     '1.0',
         COLLAPSE_INDEX: false,
         FILE_SUFFIX: '.html',
@@ -66,22 +64,24 @@ package (1.4.15-1 or later) has already supported Gnuk Token.</p>
 <p>If needed, please add lines for Gnuk Token to give a desktop user the
 permission to use the device.  We specify USB ID of Gnuk Token (by
 FSIJ):</p>
-<div class="highlight-python"><pre>--- /lib/udev/rules.d/60-gnupg.rules.orig   2012-06-24 21:51:26.000000000 +0900
+<div class="highlight-python"><div class="highlight"><pre>--- /lib/udev/rules.d/60-gnupg.rules.orig   2012-06-24 21:51:26.000000000 +0900
 +++ /lib/udev/rules.d/60-gnupg.rules        2012-07-13 17:18:55.149587687 +0900
 @@ -10,4 +10,7 @@
- ATTR{idVendor}=="04e6", ATTR{idProduct}=="5115", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg"
- ATTR{idVendor}=="20a0", ATTR{idProduct}=="4107", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg"
+ ATTR{idVendor}==&quot;04e6&quot;, ATTR{idProduct}==&quot;5115&quot;, ENV{ID_SMARTCARD_READER}=&quot;1&quot;, ENV{ID_SMARTCARD_READER_DRIVER}=&quot;gnupg&quot;
+ ATTR{idVendor}==&quot;20a0&quot;, ATTR{idProduct}==&quot;4107&quot;, ENV{ID_SMARTCARD_READER}=&quot;1&quot;, ENV{ID_SMARTCARD_READER_DRIVER}=&quot;gnupg&quot;
 
 +# Gnuk
-+ATTR{idVendor}=="234b", ATTR{idProduct}=="0000", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg"
++ATTR{idVendor}==&quot;234b&quot;, ATTR{idProduct}==&quot;0000&quot;, ENV{ID_SMARTCARD_READER}=&quot;1&quot;, ENV{ID_SMARTCARD_READER_DRIVER}=&quot;gnupg&quot;
 +
- LABEL="gnupg_rules_end"</pre>
+ LABEL=&quot;gnupg_rules_end&quot;
+</pre></div>
 </div>
 <p>When we install &#8220;gnupg2&#8221; package only (with no &#8220;gnupg&#8221; package),
 there will be no udev rules (there is a bug report #543217 for this issue).
 In this case, we need something like this in /etc/udev/rules.d/60-gnuk.rules:</p>
-<div class="highlight-python"><pre>SUBSYSTEMS=="usb", ATTRS{idVendor}=="234b", ATTRS{idProduct}=="0000",   \
-ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg"</pre>
+<div class="highlight-python"><div class="highlight"><pre>SUBSYSTEMS==&quot;usb&quot;, ATTRS{idVendor}==&quot;234b&quot;, ATTRS{idProduct}==&quot;0000&quot;,   \
+ENV{ID_SMARTCARD_READER}=&quot;1&quot;, ENV{ID_SMARTCARD_READER_DRIVER}=&quot;gnupg&quot;
+</pre></div>
 </div>
 <p>Usually, udev daemon automatically handles for the changes of configuration
 files.  If not, please let the daemon reload rules:</p>
@@ -93,7 +93,8 @@ files.  If not, please let the daemon reload rules:</p>
 <h2>udev rules for ST-Link/V2<a class="headerlink" href="#udev-rules-for-st-link-v2" title="Permalink to this headline">¶</a></h2>
 <p>For development of Gnuk, we use ST-Link/V2 as JTAG/SWD debugger.
 We need to have a udev rule for ST-Link/V2.  It&#8217;s like:</p>
-<div class="highlight-python"><pre>ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="3748", GROUP="tape", MODE="664", SYMLINK+="stlink"</pre>
+<div class="highlight-python"><div class="highlight"><pre>ACTION==&quot;add&quot;, SUBSYSTEM==&quot;usb&quot;, ATTR{idVendor}==&quot;0483&quot;, ATTR{idProduct}==&quot;3748&quot;, GROUP=&quot;tape&quot;, MODE=&quot;664&quot;, SYMLINK+=&quot;stlink&quot;
+</pre></div>
 </div>
 <p>I have this in the file /etc/udev/rules.d/10-stlink.rules.</p>
 </div>
@@ -159,7 +160,7 @@ We need to have a udev rule for ST-Link/V2.  It&#8217;s like:</p>
     </div>
     <div class="footer">
         &copy; Copyright 2012, NIIBE Yutaka.
-      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.3.
     </div>
   </body>
 </html>
\ No newline at end of file
index 65b0e1e..ea0d5e7 100644 (file)
@@ -1,5 +1,3 @@
-
-
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
@@ -15,7 +13,7 @@
     
     <script type="text/javascript">
       var DOCUMENTATION_OPTIONS = {
-        URL_ROOT:    '',
+        URL_ROOT:    './',
         VERSION:     '1.0',
         COLLAPSE_INDEX: false,
         FILE_SUFFIX: '.html',
@@ -27,7 +25,7 @@
     <script type="text/javascript" src="_static/doctools.js"></script>
     <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
     <link rel="top" title="Gnuk Documentation 1.0 documentation" href="index.html" />
-    <link rel="next" title="GnuPG settings for GNOME 3" href="gnome3-gpg-settings.html" />
+    <link rel="next" title="GnuPG settings for GNOME 3.1x and GNOME 3.0" href="gnome3-gpg-settings.html" />
     <link rel="prev" title="Set up your passphrase for your Gnuk Token" href="gnuk-passphrase-setting.html" /> 
   </head>
   <body>
@@ -38,7 +36,7 @@
           <a href="genindex.html" title="General Index"
              accesskey="I">index</a></li>
         <li class="right" >
-          <a href="gnome3-gpg-settings.html" title="GnuPG settings for GNOME 3"
+          <a href="gnome3-gpg-settings.html" title="GnuPG settings for GNOME 3.1x and GNOME 3.0"
              accesskey="N">next</a> |</li>
         <li class="right" >
           <a href="gnuk-passphrase-setting.html" title="Set up your passphrase for your Gnuk Token"
@@ -63,7 +61,7 @@ while <tt class="docutils literal"><span class="pre">.gnupg</span></tt> director
 <p>Using the Token, we need to put the public key and the secret
 key reference (to the token) in <tt class="docutils literal"><span class="pre">.gnupg</span></tt>.</p>
 <p>To do that, invoke GnuPG with <tt class="docutils literal"><span class="pre">--card-edit</span></tt> option.</p>
-<div class="highlight-python"><pre>$ gpg --card-edit
+<div class="highlight-python"><div class="highlight"><pre>$ gpg --card-edit
 Application ID ...: D276000124010200F517000000010000
 Version ..........: 2.0
 Manufacturer .....: FSIJ
@@ -86,25 +84,27 @@ Authentication key: B4D9 7142 C42D 6802 F5F7  4E70 9C33 B6BA 5BB0 65DC
       created ....: 2010-10-22 06:06:36
 General key info..: [none]
 
-gpg/card&gt;</pre>
+gpg/card&gt;
+</pre></div>
 </div>
 <p>It says, there is no key info related to this token on your PC (<tt class="docutils literal"><span class="pre">[none]</span></tt>).</p>
 <p>Fetch the public key from URL specified in the Token.</p>
-<div class="highlight-python"><pre>gpg/card&gt; fetch
+<div class="highlight-python"><div class="highlight"><pre>gpg/card&gt; fetch
 gpg: requesting key 4CA7BABE from http server www.gniibe.org
-gpg: key 4CA7BABE: public key "NIIBE Yutaka &lt;gniibe@fsij.org&gt;" imported
+gpg: key 4CA7BABE: public key &quot;NIIBE Yutaka &lt;gniibe@fsij.org&gt;&quot; imported
 gpg: no ultimately trusted keys found
 gpg: Total number processed: 1
 gpg:               imported: 1  (RSA: 1)
 
-gpg/card&gt;</pre>
+gpg/card&gt;
+</pre></div>
 </div>
 <p>Good.  The public key is now in <tt class="docutils literal"><span class="pre">.gnupg</span></tt>.  We can examine by <tt class="docutils literal"><span class="pre">gpg</span> <span class="pre">--list-keys</span></tt>.</p>
 <p>However, the secret key reference (to the token) is not in <tt class="docutils literal"><span class="pre">.gnupg</span></tt> yet.</p>
 <p>It will be generated when I do <tt class="docutils literal"><span class="pre">--card-status</span></tt> by GnuPG with
 correspoinding public key in <tt class="docutils literal"><span class="pre">.gnupg</span></tt>, or just type return
 at the <tt class="docutils literal"><span class="pre">gpg/card&gt;</span></tt> prompt.</p>
-<div class="highlight-python"><pre>gpg/card&gt;
+<div class="highlight-python"><div class="highlight"><pre>gpg/card&gt;
 
 Application ID ...: D276000124010200F517000000010000
 Version ..........: 2.0
@@ -135,7 +135,8 @@ ssb&gt;  2048R/084239CF  created: 2010-10-15  expires: never
 ssb&gt;  2048R/5BB065DC  created: 2010-10-22  expires: never
                       card-no: F517 00000001
 
-gpg/card&gt;</pre>
+gpg/card&gt;
+</pre></div>
 </div>
 <p>OK, now I can use the Token on this computer.</p>
 </div>
@@ -144,7 +145,7 @@ gpg/card&gt;</pre>
 <p>Yes, I can use the Token by the public key and the secret
 key reference to the card.  More, I need to update the trustdb.</p>
 <p>To do that I do:</p>
-<div class="highlight-python"><pre>$ gpg --edit-key 4ca7babe
+<div class="highlight-python"><div class="highlight"><pre>$ gpg --edit-key 4ca7babe
 gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc.
 This is free software: you are free to change and redistribute it.
 There is NO WARRANTY, to the extent permitted by law.
@@ -158,10 +159,11 @@ sub  2048R/5BB065DC  created: 2010-10-22  expires: never       usage: A
 [ unknown] (1). NIIBE Yutaka &lt;gniibe@fsij.org&gt;
 [ unknown] (2)  NIIBE Yutaka &lt;gniibe@debian.org&gt;
 
-gpg&gt;</pre>
+gpg&gt;
+</pre></div>
 </div>
 <p>See, the key is <tt class="docutils literal"><span class="pre">unknown</span></tt> state.  Add trust for that.</p>
-<div class="highlight-python"><pre>gpg&gt; trust
+<div class="highlight-python"><div class="highlight"><pre>gpg&gt; trust
 pub  2048R/4CA7BABE  created: 2010-10-15  expires: never       usage: SC
                      trust: unknown       validity: unknown
 sub  2048R/084239CF  created: 2010-10-15  expires: never       usage: E
@@ -169,10 +171,10 @@ sub  2048R/5BB065DC  created: 2010-10-22  expires: never       usage: A
 [ unknown] (1). NIIBE Yutaka &lt;gniibe@fsij.org&gt;
 [ unknown] (2)  NIIBE Yutaka &lt;gniibe@debian.org&gt;
 
-Please decide how far you trust this user to correctly verify other users' keys
+Please decide how far you trust this user to correctly verify other users&#39; keys
 (by looking at passports, checking fingerprints from different sources, etc.)
 
-  1 = I don't know or won't say
+  1 = I don&#39;t know or won&#39;t say
   2 = I do NOT trust
   3 = I trust marginally
   4 = I trust fully
@@ -191,10 +193,11 @@ sub  2048R/5BB065DC  created: 2010-10-22  expires: never       usage: A
 Please note that the shown key validity is not necessarily correct
 unless you restart the program.
 
-$</pre>
+$
+</pre></div>
 </div>
 <p>Next time I invoke GnuPG, it will be <tt class="docutils literal"><span class="pre">ultimate</span></tt> key.  Let&#8217;s see:</p>
-<div class="highlight-python"><pre>$ gpg --edit-key 4ca7babe
+<div class="highlight-python"><div class="highlight"><pre>$ gpg --edit-key 4ca7babe
 gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc.
 This is free software: you are free to change and redistribute it.
 There is NO WARRANTY, to the extent permitted by law.
@@ -209,7 +212,8 @@ sub  2048R/5BB065DC  created: 2010-10-22  expires: never       usage: A
 [ultimate] (2)  NIIBE Yutaka &lt;gniibe@debian.org&gt;
 
 gpg&gt; quit
-$</pre>
+$
+</pre></div>
 </div>
 </div>
 </div>
@@ -234,7 +238,7 @@ $</pre>
                         title="previous chapter">Set up your passphrase for your Gnuk Token</a></p>
   <h4>Next topic</h4>
   <p class="topless"><a href="gnome3-gpg-settings.html"
-                        title="next chapter">GnuPG settings for GNOME 3</a></p>
+                        title="next chapter">GnuPG settings for GNOME 3.1x and GNOME 3.0</a></p>
   <h3>This Page</h3>
   <ul class="this-page-menu">
     <li><a href="_sources/using-gnuk-token-with-another-computer.txt"
@@ -264,7 +268,7 @@ $</pre>
           <a href="genindex.html" title="General Index"
              >index</a></li>
         <li class="right" >
-          <a href="gnome3-gpg-settings.html" title="GnuPG settings for GNOME 3"
+          <a href="gnome3-gpg-settings.html" title="GnuPG settings for GNOME 3.1x and GNOME 3.0"
              >next</a> |</li>
         <li class="right" >
           <a href="gnuk-passphrase-setting.html" title="Set up your passphrase for your Gnuk Token"
@@ -274,7 +278,7 @@ $</pre>
     </div>
     <div class="footer">
         &copy; Copyright 2012, NIIBE Yutaka.
-      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.3.
     </div>
   </body>
 </html>
\ No newline at end of file