Update Gnuk documentation.
authorNIIBE Yutaka <gniibe@fsij.org>
Thu, 25 Jan 2018 01:40:49 +0000 (10:40 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Thu, 25 Jan 2018 01:40:49 +0000 (10:40 +0900)
55 files changed:
doc-gnuk/.buildinfo [new file with mode: 0644]
doc-gnuk/_sources/development.txt
doc-gnuk/_sources/generating-2048-RSA-key.txt [deleted file]
doc-gnuk/_sources/generating-key.txt [new file with mode: 0644]
doc-gnuk/_sources/gnome3-gpg-settings.txt [deleted file]
doc-gnuk/_sources/gnuk-keytocard-noremoval.txt
doc-gnuk/_sources/gnuk-keytocard.txt
doc-gnuk/_sources/gnuk-passphrase-setting.txt
doc-gnuk/_sources/gnuk-personalization.txt
doc-gnuk/_sources/gnuk-token-initial-configuration.txt
doc-gnuk/_sources/gpg-settings.txt
doc-gnuk/_sources/index.txt
doc-gnuk/_sources/intro.txt
doc-gnuk/_sources/stop-scdaemon.txt
doc-gnuk/_sources/udev-rules.txt
doc-gnuk/_sources/using-gnuk-token-with-another-computer.txt
doc-gnuk/_static/basic.css
doc-gnuk/_static/classic.css [new file with mode: 0644]
doc-gnuk/_static/comment-bright.png
doc-gnuk/_static/comment-close.png
doc-gnuk/_static/comment.png
doc-gnuk/_static/default.css
doc-gnuk/_static/doctools.js
doc-gnuk/_static/down-pressed.png
doc-gnuk/_static/down.png
doc-gnuk/_static/file.png
doc-gnuk/_static/jquery.js
doc-gnuk/_static/minus.png
doc-gnuk/_static/plus.png
doc-gnuk/_static/pygments.css
doc-gnuk/_static/searchtools.js
doc-gnuk/_static/sidebar.js
doc-gnuk/_static/underscore.js
doc-gnuk/_static/up-pressed.png
doc-gnuk/_static/up.png
doc-gnuk/_static/websupport.js
doc-gnuk/development.html
doc-gnuk/generating-2048-RSA-key.html [deleted file]
doc-gnuk/generating-key.html [new file with mode: 0644]
doc-gnuk/genindex.html
doc-gnuk/gnome3-gpg-settings.html [deleted file]
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
doc-gnuk/search.html
doc-gnuk/searchindex.js
doc-gnuk/stop-scdaemon.html
doc-gnuk/udev-rules.html
doc-gnuk/using-gnuk-token-with-another-computer.html

diff --git a/doc-gnuk/.buildinfo b/doc-gnuk/.buildinfo
new file mode 100644 (file)
index 0000000..852ca26
--- /dev/null
@@ -0,0 +1,4 @@
+# Sphinx build info version 1
+# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
+config: 71d6f92a2112e244a895cd80d2de19b1
+tags: 645f666f9bcd5a90fca523b33c5a78b7
index 9b03f9c..19eb69b 100644 (file)
@@ -22,34 +22,29 @@ tool/stlinkv2.py.
 OpenOCD
 -------
 
-For JTAG/SWD debugger, we can use OpenOCD somehow.
-
-Note that ST-Link/V2 was *not* supported by OpenOCD 0.5.0.
-
-It is supported by version 0.6 or later somehow, but still, you can't
-enable protection of flash ROM with OpenOCD using ST-Link/V2.
+For JTAG/SWD debugger, we can use OpenOCD.
 
 
 GNU Toolchain
 -------------
 
 You need GNU toolchain and newlib for 'arm-none-eabi' target.
+In Debian, we can just apt-get packages of: gcc-arm-none-eabi, binutils-arm-none-eabi, gdb-arm-none-eabi and libnewlib-arm-none-eabi. 
 
-There is "gcc-arm-embedded" project.  See:
+For other distributiions, there is "gcc-arm-embedded" project.  See:
 https://launchpad.net/gcc-arm-embedded/
 
-It is based on GCC 4.8 (as of December, 2013).  We are using "-O3 -Os"
-for compiler option.
+We are using "-O3 -Os" for compiler option.
 
 
 Building Gnuk
 -------------
 
-Change directory to ``src``:
+Change directory to ``src``: ::
 
   $ cd gnuk-VERSION/src
 
-Then, run ``configure``:
+Then, run ``configure``: ::
 
   $ ./configure --vidpid=<VID:PID>
 
@@ -57,8 +52,12 @@ Here, you need to specify USB vendor ID and product ID.  For FSIJ's,
 it's: --vidpid=234b:0000 .  Please read the section 'USB vendor ID and
 product ID' in README.
 
-Type:
+Type: ::
 
   $ make
 
 Then, we will have "gnuk.elf" under src/build directory.
+
+Next, we can get the final image by running following command. ::
+
+  $ make build/gnuk-vidpid.elf
diff --git a/doc-gnuk/_sources/generating-2048-RSA-key.txt b/doc-gnuk/_sources/generating-2048-RSA-key.txt
deleted file mode 100644 (file)
index 46d3b99..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-============================
-Generating 2048-bit RSA keys
-============================
-
-In this section, we describe how to generate 2048-bit RSA keys.
-
-
-Key length of RSA
-=================
-
-In 2005, NIST (National Institute of Standards and Technology, USA)
-has issued the first revision of NIST Special Publication 800-57, 
-"Recommendation for Key Management".
-
-In 800-57, NIST advises that 1024-bit RSA keys will no longer be
-viable after 2010 and advises moving to 2048-bit RSA keys.  NIST
-advises that 2048-bit keys should be viable until 2030.
-
-As of 2010, GnuPG's default for generating RSA key is 2048-bit.
-
-Some people have preference on RSA 4096-bit keys, considering
-"longer is better".
-
-However, "longer is better" is not always true.  When it's long, it
-requires more computational resource, memory and storage, and it
-consumes more power for nomal usages.  These days, many people has
-enough computational resource, that would be true, but less is better
-for power consumption.
-
-For security, the key length is just a single factor.  We had and will have
-algorithm issues, too.  It is true that it's difficult to update
-our public keys, but this problem wouldn't be solved by just have
-longer keys.
-
-We deliberately support only RSA 2048-bit keys for Gnuk, considering
-device computation power and host software constraints.
-
-Thus, the key size is 2048-bit in the examples below.
-
-
-Generating keys on host PC
-==========================
-
-Here is the example session to generate main key and a subkey for encryption.
-
-I invoke GnuPG with ``--gen-key`` option. ::
-
-  $ 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.
-
-and GnuPG asks kind of key.  Select ``RSA and RSA``. ::
-
-  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.
-
-and select 2048-bit (as Gnuk Token only supports this). ::
-
-  What keysize do you want? (2048) 
-  Requested keysize is 2048 bits
-
-and select expiration of the key. ::
-
-  Please specify how long the key should be valid.
-           0 = key does not expire
-        <n>  = key expires in n days
-        <n>w = key expires in n weeks
-        <n>m = key expires in n months
-        <n>y = key expires in n years
-  Key is valid for? (0) 0
-  Key does not expire at all
-
-Confirm key types, bitsize and expiration. ::
-
-  Is this correct? (y/N) y
-
-Then enter user ID. ::
-
-  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) <heinrichh@duesseldorf.de>"
-  
-  Real name: Niibe Yutaka
-  Email address: gniibe@fsij.org
-  Comment: 
-  You selected this USER-ID:
-      "Niibe Yutaka <gniibe@fsij.org>"
-  
-  Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
-
-and enter passphrase for this **key on host PC**.
-Note that this is a passphrase for the key on host PC.
-It is different thing to the passphrase of Gnuk Token.
-
-We enter two same inputs two times
-(once for passphrase input, and another for confirmation). ::
-
-  You need a Passphrase to protect your secret key.
-  <PASSWORD-KEY-ON-PC>
-
-Then, GnuPG generate keys.  It takes some time.  ::
-
-  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.
-  ...+++++
-  +++++
-  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.
-  ..+++++
-  
-  Not enough random bytes available.  Please do some other work to give
-  the OS a chance to collect more entropy! (Need 15 more bytes)
-  ...+++++
-  gpg: key 4CA7BABE marked as ultimately trusted
-  public and secret key created and signed.
-  
-  gpg: checking the trustdb
-  gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
-  pub   2048R/4CA7BABE 2010-10-15
-        Key fingerprint = 1241 24BD 3B48 62AF 7A0A  42F1 00B4 5EBD 4CA7 BABE
-  uid                  Niibe Yutaka <gniibe@fsij.org>
-  sub   2048R/084239CF 2010-10-15
-  $ 
-
-Done.
-
-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 ``--expert`` option for GnuPG. ::
-
-  $ 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.
-  
-  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   
-  [ultimate] (1). Niibe Yutaka <gniibe@fsij.org>
-  
-  gpg> 
-
-Here, it displays that there are main key and a subkey.
-It prompts sub-command with ``gpg>`` .
-
-Here, we enter ``addkey`` sub-command.
-Then, we enter the passphrase of **key on host PC**.
-It's the one we entered above as <PASSWORD-KEY-ON-PC>. ::
-
-  gpg> addkey
-  Key is protected.
-    
-  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-ON-PC>
-  gpg: gpg-agent is not available in this session
-
-GnuPG asks kind of key.  We select ``RSA (set your own capabilities)``. ::
-
-  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
-
-And select ``Authenticate`` for the capabilities for this key.
-Initially, it's ``Sign`` and  ``Encrypt``.
-I need to deselect ``Sign`` and ``Encrypt``, and select ``Authenticate``.
-To do that, I enter ``s``, ``e``, and ``a``.  ::
-
-  Possible actions for a RSA key: Sign Encrypt Authenticate 
-  Current allowed actions: Sign Encrypt 
-  
-     (S) Toggle the sign capability
-     (E) Toggle the encrypt capability
-     (A) Toggle the authenticate capability
-     (Q) Finished
-  
-  Your selection? s
-  
-  Possible actions for a RSA key: Sign Encrypt Authenticate 
-  Current allowed actions: Encrypt 
-  
-     (S) Toggle the sign capability
-     (E) Toggle the encrypt capability
-     (A) Toggle the authenticate capability
-     (Q) Finished
-  
-  Your selection? e
-  
-  Possible actions for a RSA key: Sign Encrypt Authenticate 
-  Current allowed actions: 
-
-     (S) Toggle the sign capability
-     (E) Toggle the encrypt capability
-     (A) Toggle the authenticate capability
-     (Q) Finished
-  
-  Your selection? a
-  
-  Possible actions for a RSA key: Sign Encrypt Authenticate 
-  Current allowed actions: Authenticate 
-  
-     (S) Toggle the sign capability
-     (E) Toggle the encrypt capability
-     (A) Toggle the authenticate capability
-     (Q) Finished
-
-OK, we set the capability of ``Authenticate``.
-We enter ``q`` to finish setting capabilities. ::
-
-  Your selection? q
-
-GnuPG asks bitsize and expiration, we enter 2048 for bitsize and no expiration.
-Then, we confirm that we really create the key. ::
-
-  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.
-           0 = key does not expire
-        <n>  = key expires in n days
-        <n>w = key expires in n weeks
-        <n>m = key expires in n months
-        <n>y = key expires in n years
-  Key is valid for? (0) 0
-  Key does not expire at all
-  Is this correct? (y/N) y
-  Really create? (y/N) y
-
-Then, GnuPG generate the key. ::
-
-  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.
-  .......+++++
-  +++++
-
-  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>
-
-  gpg> 
-
-We save the key (to the storage of the host PC. ::
-
-  gpg> save
-  $ 
-
-Now, we have three keys (one primary key for signature and certification,
-subkey for encryption, and another subkey for authentication).
-
-
-Publishing public key
-=====================
-
-We make a file for the public key by ``--export`` option of GnuPG. ::
-
-  $ gpg --armor --output <YOUR-KEY>.asc --export <YOUR-KEY-ID>
-
-We can publish the file by web server.  Or we can publish the key
-to a keyserver, by invoking GnuPG with ``--send-keys`` option.  ::
-
-  $ gpg --keyserver pool.sks-keyservers.net --send-keys <YOUR-KEY-ID>
-
-Here, pool.sks-keyservers.net is a keyserver, which is widely used.
-
-
-Backup the private key
-======================
-
-There are some ways to back up private key, such that backup .gnupg
-directory entirely, or use of paperkey, etc.
-Here, we describe backup by ASCII file.
-ASCII file is good, because it has less risk on transfer.
-Binary file has a risk to be modified on transfer.
-
-Note that the key on host PC is protected by passphrase (which
-is <PASSWORD-KEY-ON-PC> in the example above).  Using the key
-from the backup needs this passphrase.  It is common that
-people will forget passphrase for backup.  Never forget it.
-You have been warned.
-
-To make ASCII backup for private key,
-invokde GnuPG with ``--armor`` option and ``--export-secret-keys``
-specifying the key identifier. ::
-
-  $ gpg --armor --output <YOUR-SECRET>.asc --export-secret-keys <YOUR-KEY-ID>
-
-From the backup,
-we can recover privet key by invoking GnuPG with ``--import`` option. ::
-
-  $ gpg --import <YOUR-SECRET>.asc
diff --git a/doc-gnuk/_sources/generating-key.txt b/doc-gnuk/_sources/generating-key.txt
new file mode 100644 (file)
index 0000000..ede0b6e
--- /dev/null
@@ -0,0 +1,487 @@
+====================
+Generating key pairs
+====================
+
+In this section, we describe how to generate 2048-bit RSA keys.
+
+You would like to use newer ECC keys instead of RSA keys.  It is also described.
+
+
+Key length of RSA
+=================
+
+In 2005, NIST (National Institute of Standards and Technology, USA)
+issued the first revision of NIST Special Publication 800-57, 
+"Recommendation for Key Management".
+
+In 800-57, NIST advises that 1024-bit RSA keys will no longer be
+viable after 2010 and advises moving to 2048-bit RSA keys.  NIST
+advises that 2048-bit keys should be viable until 2030.
+
+As of 2016, GnuPG's default for generating RSA key is 2048-bit.
+
+Some people have preference on RSA 4096-bit keys, considering "longer is better".
+
+However, "longer is better" is not always true.  When it's long, it
+requires more computational resource, memory, and storage.  Further,
+it consumes more power for nomal usages.  These days, many people has
+enough computational resource, that would be true, but less is better
+for power consumption, isn't it?
+
+For security, the key length is just a single factor.  We had and will have
+algorithm issues, too.  It is true that it's difficult to update
+our public keys, but this problem wouldn't be solved by just having
+longer keys.
+
+We deliberately recommend use of RSA 2048-bit keys for Gnuk,
+considering device computation power and host software constraints.
+
+Thus, the key size is 2048-bit in the examples below.
+
+When/If your environment allows use of newer ECC keys, newer ECC keys are recommended.
+
+
+Generating RSA keys on host PC
+==============================
+
+Here is the example session to generate main key and a subkey for encryption.
+
+I invoke GnuPG with ``--quick-gen-key`` option. ::
+
+  $ gpg --quick-gen-key "Niibe Yutaka <gniibe@fsij.org>"
+  About to create a key for:
+      "Niibe Yutaka <gniibe@fsij.org>"
+
+  Continue? (Y/n) y
+
+It askes passphrase for this **key on host PC**.
+Note that this is a passphrase for the key on host PC.
+It is different thing to the passphrase of Gnuk Token.
+We enter two same inputs two times
+(once for passphrase input, and another for confirmation),
+<PASSWORD-KEY-ON-PC>.
+
+Then, GnuPG generate keys.  It takes some time.  ::
+  
+  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.
+  gpg: key 76A9392B02CD15D1 marked as ultimately trusted
+  gpg: revocation certificate stored as '/home/gniibe.gnupg/openpgp-revocs.d/36CE0B8408CFE5CD07F94ACF76A9392B02CD15D1.rev'
+  public and secret key created and signed.
+
+  gpg: checking the trustdb
+  gpg: marginals needed: 3  completes needed: 1  trust model: pgp
+  gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
+  pub   rsa2048 2016-06-20 [S]
+        36CE0B8408CFE5CD07F94ACF76A9392B02CD15D1
+  uid           [ultimate] Niibe Yutaka <gniibe@fsij.org>
+  sub   rsa2048 2016-06-20 []
+
+Done.
+
+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 ``--expert`` option for GnuPG. ::
+
+  gpg (GnuPG) 2.1.13; Copyright (C) 2016 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.
+
+  sec  rsa2048/76A9392B02CD15D1
+       created: 2016-06-20  expires: never       usage: SC  
+       trust: ultimate      validity: ultimate
+  ssb  rsa2048/4BD1EB26F0E607E6
+       created: 2016-06-20  expires: never       usage: E   
+  [ultimate] (1). Niibe Yutaka <gniibe@fsij.org>
+  
+  gpg> 
+
+Here, it displays that there are main key and a subkey.
+It prompts sub-command with ``gpg>`` .
+
+Here, we enter ``addkey`` sub-command.
+
+  gpg> addkey
+    
+GnuPG asks kind of key.  We select ``RSA (set your own capabilities)``. ::
+
+  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)
+    (10) ECC (sign only)
+    (11) ECC (set your own capabilities)
+    (12) ECC (encrypt only)
+    (13) Existing key
+  Your selection? 8
+
+And select ``Authenticate`` for the capabilities for this key.
+Initially, it's ``Sign`` and  ``Encrypt``.
+I need to deselect ``Sign`` and ``Encrypt``, and select ``Authenticate``.
+To do that, I enter ``s``, ``e``, and ``a``.  ::
+
+  Possible actions for a RSA key: Sign Encrypt Authenticate 
+  Current allowed actions: Sign Encrypt 
+  
+     (S) Toggle the sign capability
+     (E) Toggle the encrypt capability
+     (A) Toggle the authenticate capability
+     (Q) Finished
+  
+  Your selection? s
+  
+  Possible actions for a RSA key: Sign Encrypt Authenticate 
+  Current allowed actions: Encrypt 
+  
+     (S) Toggle the sign capability
+     (E) Toggle the encrypt capability
+     (A) Toggle the authenticate capability
+     (Q) Finished
+  
+  Your selection? e
+  
+  Possible actions for a RSA key: Sign Encrypt Authenticate 
+  Current allowed actions: 
+
+     (S) Toggle the sign capability
+     (E) Toggle the encrypt capability
+     (A) Toggle the authenticate capability
+     (Q) Finished
+  
+  Your selection? a
+  
+  Possible actions for a RSA key: Sign Encrypt Authenticate 
+  Current allowed actions: Authenticate 
+  
+     (S) Toggle the sign capability
+     (E) Toggle the encrypt capability
+     (A) Toggle the authenticate capability
+     (Q) Finished
+
+OK, we set the capability of ``Authenticate``.
+We enter ``q`` to finish setting capabilities. ::
+
+  Your selection? q
+
+GnuPG asks bitsize and expiration, we enter 2048 for bitsize and no expiration.
+Then, we confirm that we really create the key. ::
+
+  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.
+           0 = key does not expire
+        <n>  = key expires in n days
+        <n>w = key expires in n weeks
+        <n>m = key expires in n months
+        <n>y = key expires in n years
+  Key is valid for? (0) 0
+  Key does not expire at all
+  Is this correct? (y/N) y
+  Really create? (y/N) y
+
+Then, it askes the passphrase, it is the passphrase of **key on host PC**.
+It's the one we entered above as <PASSWORD-KEY-ON-PC>.
+
+Then, GnuPG generate the key. ::
+
+  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.
+
+  sec  rsa2048/76A9392B02CD15D1
+       created: 2016-06-20  expires: never       usage: SC  
+       trust: ultimate      validity: ultimate
+  ssb  rsa2048/4BD1EB26F0E607E6
+       created: 2016-06-20  expires: never       usage: E   
+  ssb  rsa2048/F3BA52C64012198D
+       created: 2016-06-20  expires: never       usage: A   
+  [ultimate] (1). Niibe Yutaka <gniibe@fsij.org>
+
+  gpg> 
+
+We save the key (to the storage of the host PC). ::
+
+  gpg> save
+  $ 
+
+Now, we have three keys (one primary key for signature and certification,
+subkey for encryption, and another subkey for authentication).
+
+
+Publishing public key
+=====================
+
+We make a file for the public key by ``--export`` option of GnuPG. ::
+
+  $ gpg --armor --output <YOUR-KEY>.asc --export <YOUR-KEY-ID>
+
+We can publish the file by web server.  Or we can publish the key
+to a keyserver, by invoking GnuPG with ``--send-keys`` option.  ::
+
+  $ gpg --keyserver pool.sks-keyservers.net --send-keys <YOUR-KEY-ID>
+
+Here, pool.sks-keyservers.net is a keyserver, which is widely used.
+
+
+Backup the private key
+======================
+
+There are some ways to back up private key, such that backup .gnupg
+directory entirely, or use of paperkey, etc.
+Here, we describe backup by ASCII file.
+ASCII file is good, because it has less risk on transfer.
+Binary file has a risk to be modified on transfer.
+
+Note that the key on host PC is protected by passphrase (which
+is <PASSWORD-KEY-ON-PC> in the example above).  Using the key
+from the backup needs this passphrase.  It is common that
+people will forget passphrase for backup.  Never forget it.
+You have been warned.
+
+To make ASCII backup for private key,
+invokde GnuPG with ``--armor`` option and ``--export-secret-keys``
+specifying the key identifier. ::
+
+  $ gpg --armor --output <YOUR-SECRET>.asc --export-secret-keys <YOUR-KEY-ID>
+
+From the backup,
+we can recover privet key by invoking GnuPG with ``--import`` option. ::
+
+  $ gpg --import <YOUR-SECRET>.asc
+
+
+Generating ECC keys on host PC
+==============================
+
+Here is an example session log to create newer ECC keys.  You need
+libgcrypt 1.7 or newer and GnuPG 2.1.8 or newer.
+
+Next, we invoke gpg frontend with ``--expert`` and ``--full-gen-key`` option. ::
+
+    $ gpg --expert --full-gen-key
+    gpg (GnuPG) 2.1.13; Copyright (C) 2016 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.
+
+Then, we input ``9`` to select ECC primary key and ECC encryption subkey. ::
+    
+    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)
+       (7) DSA (set your own capabilities)
+       (8) RSA (set your own capabilities)
+       (9) ECC and ECC
+      (10) ECC (sign only)
+      (11) ECC (set your own capabilities)
+    Your selection? 9
+
+Next is the important selection.  We input ``1`` to select "Curve25519". ::
+
+    Please select which elliptic curve you want:
+       (1) Curve 25519
+       (2) NIST P-256
+       (3) NIST P-384
+       (4) NIST P-521
+       (5) Brainpool P-256
+       (6) Brainpool P-384
+       (7) Brainpool P-512
+       (8) secp256k1
+    Your selection? 1
+
+You may see WARNING (it depends on version of GnuPG) and may been asked.  Since it is what you want, please answer with 'y'. ::
+
+    gpg: WARNING: Curve25519 is not yet part of the OpenPGP standard.
+    Use this curve anyway? (y/N) y
+
+It asks about expiration of key. ::
+
+    Please specify how long the key should be valid.
+             0 = key does not expire
+          <n>  = key expires in n days
+          <n>w = key expires in n weeks
+          <n>m = key expires in n months
+          <n>y = key expires in n years
+    Key is valid for? (0) 
+    Key does not expire at all
+    Is this correct? (y/N) y
+
+Then, it asks about a user ID. ::
+
+    GnuPG needs to construct a user ID to identify your key.
+    
+    Real name: Kunisada Chuji
+    Email address: chuji@gniibe.org
+    Comment: 
+    You selected this USER-ID:
+        "Kunisada Chuji <chuji@gniibe.org>"
+
+Lastly, it asks confirmation. ::
+
+    Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
+
+Then, it goes like this. ::
+
+    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.
+    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.
+
+It asks the passphrase for keys by pop-up window, and then, finishes. ::
+    
+    gpg: key 17174C1A7C406DB5 marked as ultimately trusted
+    gpg: revocation certificate stored as '/home/gniibe.gnupg/openpgp-revocs.d/1719874a4fe5a1d8c465277d5a1bb27e3000f4ff.rev'
+    public and secret key created and signed.
+    
+    gpg: checking the trustdb
+    gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
+    gpg: depth: 0  valid:   6  signed:  67  trust: 0-, 0q, 0n, 0m, 0f, 6u
+    gpg: depth: 1  valid:  67  signed:  40  trust: 67-, 0q, 0n, 0m, 0f, 0u
+    gpg: next trustdb check due at 2016-10-05
+    pub   ed25519 2016-07-08
+          F478770235B60A230BE78005006A236C292C31D7
+    uid         [ultimate] Kunisada Chuji <chuji@gniibe.org>
+    sub   cv25519 2016-07-08
+    
+    $
+
+We have the primary key with ed25519, and encryption subkey with cv25519.
+
+
+Next, we add authentication subkey which can be used with OpenSSH.
+We invoke gpg frontend with ``--edit-key`` and the key ID. ::
+
+    $ gpg2 --expert --edit-key 17174C1A7C406DB5
+    gpg (GnuPG) 2.1.13; Copyright (C) 2016 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.
+    
+    sec  ed25519/17174C1A7C406DB5
+         created: 2016-07-08  expires: never       usage: SC  
+         trust: ultimate      validity: ultimate
+    ssb  cv25519/37A03183DF7B31B1
+         created: 2016-07-08  expires: never       usage: E   
+    [ultimate] (1). Kunisada Chuji <chuji@gniibe.org>
+
+We invoke ``addkey`` subcommand. ::
+
+    gpg> addkey
+
+It asks a kind of key, we input ``11`` to select ECC for authentication. ::
+
+    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)
+      (10) ECC (sign only)
+      (11) ECC (set your own capabilities)
+      (12) ECC (encrypt only)
+      (13) Existing key
+    Your selection? 11
+
+and then, we specify "Authenticate" capability. ::
+
+    Possible actions for a ECDSA/EdDSA key: Sign Authenticate 
+    Current allowed actions: Sign 
+    
+       (S) Toggle the sign capability
+       (A) Toggle the authenticate capability
+       (Q) Finished
+    
+    Your selection? a
+    
+    Possible actions for a ECDSA/EdDSA key: Sign Authenticate 
+    Current allowed actions: Sign Authenticate 
+    
+       (S) Toggle the sign capability
+       (A) Toggle the authenticate capability
+       (Q) Finished
+    
+    Your selection? s
+    
+    Possible actions for a ECDSA/EdDSA key: Sign Authenticate 
+    Current allowed actions: Authenticate 
+    
+       (S) Toggle the sign capability
+       (A) Toggle the authenticate capability
+       (Q) Finished
+    
+    Your selection? q
+
+Then, it asks which curve.  We input ``1`` for "Curve25519". ::
+
+    Please select which elliptic curve you want:
+       (1) Curve 25519
+       (2) NIST P-256
+       (3) NIST P-384
+       (4) NIST P-521
+       (5) Brainpool P-256
+       (6) Brainpool P-384
+       (7) Brainpool P-512
+       (8) secp256k1
+    Your selection? 1
+
+It may ask confirmation with WARNING (depends on version).  We say ``y``. ::
+
+    gpg: WARNING: Curve25519 is not yet part of the OpenPGP standard.
+    Use this curve anyway? (y/N) y
+
+It asks expiration of the key. ::
+
+    Please specify how long the key should be valid.
+             0 = key does not expire
+          <n>  = key expires in n days
+          <n>w = key expires in n weeks
+          <n>m = key expires in n months
+          <n>y = key expires in n years
+    Key is valid for? (0) 
+    Key does not expire at all
+    Is this correct? (y/N) y
+
+And the confirmation. ::
+
+    Really create? (y/N) y
+
+It goes. ::
+
+    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.
+
+It asks the passphrase.  And done. ::
+    
+    sec  ed25519/17174C1A7C406DB5
+         created: 2016-09-08  expires: never       usage: SC  
+         trust: ultimate      validity: ultimate
+    ssb  cv25519/37A03183DF7B31B1
+         created: 2016-09-08  expires: never       usage: E   
+    ssb  ed25519/4AD7D2428679DF5F
+         created: 2016-09-08  expires: never       usage: A   
+    [ultimate] (1). Kunisada Chuji <chuji@gniibe.org>
+
+We type ``save`` to exit form gpg. ::
+
+    gpg> save
+    $ 
+  
diff --git a/doc-gnuk/_sources/gnome3-gpg-settings.txt b/doc-gnuk/_sources/gnome3-gpg-settings.txt
deleted file mode 100644 (file)
index 5bb6126..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-===========================================
-GnuPG settings for GNOME 3.1x and GNOME 3.0
-===========================================
-
-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.
-
-.. _GnuPG settings: gpg-settings
-
-
-GNOME keyrings in GNOME 3.1x
-============================
-
-In the files /etc/xdg/autostart/gnome-keyring-ssh.desktop
-and /etc/xdg/autostart/gnome-keyring-gpg.desktop,
-we have a line something like: ::
-
-    OnlyShowIn=GNOME;Unity;MATE;
-
-Please edit this line to: ::
-
-    OnlyShowIn=
-
-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".
-
-Then, I can use proper gpg-agent for GnuPG Agent Service and SSH Agent Service with Gnuk Token in GNOME 3.0.
index 65704e7..b2e72ec 100644 (file)
@@ -10,7 +10,7 @@ I don't save changes on PC after keytocard.
 
 For the steps before the last step, please see `keytocard with removing keys on PC`_.
 
-.. _keytocard removing keys: gnuk-keytocard
+.. _keytocard with removing keys on PC: gnuk-keytocard
 
 Here is the session log of the last step.
 
@@ -22,4 +22,4 @@ Lastly, I quit GnuPG.  Note that I **don't** save changes. ::
   $ 
 
 All keys are imported to Gnuk Token now.
-Still, secret keys are available on PC.
+Still, secret keys are available on PC, too.
index aff8feb..13ebb30 100644 (file)
@@ -24,31 +24,29 @@ After personalization, I put my keys into the Token.
 
 Here is the session log.
 
-I invoke GnuPG with my key (4ca7babe).  ::
+I invoke GnuPG with my key (249CB3771750745D5CDD323CE267B052364F028D).  ::
 
-  $ gpg --edit-key 4ca7babe 
-  gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc.
+  $ gpg --edit-key 249CB3771750745D5CDD323CE267B052364F028D
+  gpg (GnuPG) 2.1.13; Copyright (C) 2016 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>
 
+  sec  ed25519/E267B052364F028D
+       created: 2015-08-12  expires: never       usage: SC  
+       trust: ultimate      validity: ultimate
+  ssb  cv25519/850AF040D619F240
+       created: 2015-08-12  expires: never       usage: E   
+  ssb  ed25519/5F910521FAA805B1
+       created: 2015-08-12  expires: never       usage: A   
+  [ultimate] (1). NIIBE Yutaka <gniibe@debian.org>
+  [ultimate] (2)  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> 
 
-  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>
+
+Then, GnuPG enters its own command interaction mode.  The prompt is ``gpg>``.
 
 Firstly, I import my primary key into Gnuk Token.
 I type ``keytocard`` command, answer ``y`` to confirm keyimport,
@@ -56,135 +54,129 @@ 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,
+Then, GnuPG asks two kinds of passphrases.  One is the passphrase of **keys on PC**
+and another is the passphrase of **Gnuk Token**.  Note that the passphrase of
+the token and the passphrase 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).
+Here, I assume that Gnuk Token's admin passphrase of factory setting (12345678).
 
-I enter these passwords. ::
+I enter these passphrases. ::
 
-  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 your passphrase, so that the secret key can be unlocked for this session
+  <PASSWORD-KEY-ON-PC>
   
   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.
+  sec  ed25519/E267B052364F028D
+       created: 2015-08-12  expires: never       usage: SC  
+       trust: ultimate      validity: ultimate
+  ssb  cv25519/850AF040D619F240
+       created: 2015-08-12  expires: never       usage: E   
+  ssb  ed25519/5F910521FAA805B1
+       created: 2015-08-12  expires: never       usage: A   
+  [ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
+  [ultimate] (2)  NIIBE Yutaka <gniibe@debian.org>
 
 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>
+  sec  ed25519/E267B052364F028D
+       created: 2015-08-12  expires: never       usage: SC  
+       trust: ultimate      validity: ultimate
+  ssb* cv25519/850AF040D619F240
+       created: 2015-08-12  expires: never       usage: E   
+  ssb  ed25519/5F910521FAA805B1
+       created: 2015-08-12  expires: never       usage: A   
+  [ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
+  [ultimate] (2)  NIIBE Yutaka <gniibe@debian.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.
+  Please enter your passphrase, so that the secret key can be unlocked for this session
+  <PASSWORD-KEY-ON-PC>
   
+  sec  ed25519/E267B052364F028D
+       created: 2015-08-12  expires: never       usage: SC  
+       trust: ultimate      validity: ultimate
+  ssb* cv25519/850AF040D619F240
+       created: 2015-08-12  expires: never       usage: E   
+  ssb  ed25519/5F910521FAA805B1
+       created: 2015-08-12  expires: never       usage: A   
+  [ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
+  [ultimate] (2)  NIIBE Yutaka <gniibe@debian.org>
+
+The sub key is now on the Token.
+
 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>
+  sec  ed25519/E267B052364F028D
+       created: 2015-08-12  expires: never       usage: SC  
+       trust: ultimate      validity: ultimate
+  ssb  cv25519/850AF040D619F240
+       created: 2015-08-12  expires: never       usage: E   
+  ssb  ed25519/5F910521FAA805B1
+       created: 2015-08-12  expires: never       usage: A   
+  [ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
+  [ultimate] (2)  NIIBE Yutaka <gniibe@debian.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>
+  sec  ed25519/E267B052364F028D
+       created: 2015-08-12  expires: never       usage: SC  
+       trust: ultimate      validity: ultimate
+  ssb  cv25519/850AF040D619F240
+       created: 2015-08-12  expires: never       usage: E   
+  ssb* ed25519/5F910521FAA805B1
+       created: 2015-08-12  expires: never       usage: A   
+  [ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
+  [ultimate] (2)  NIIBE Yutaka <gniibe@debian.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
+  Please enter your passphrase, so that the secret key can be unlocked for this session
+  <PASSWORD-KEY-ON-PC>
   
-  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.
+  sec  ed25519/E267B052364F028D
+       created: 2015-08-12  expires: never       usage: SC  
+       trust: ultimate      validity: ultimate
+  ssb  cv25519/850AF040D619F240
+       created: 2015-08-12  expires: never       usage: E   
+  ssb* ed25519/5F910521FAA805B1
+       created: 2015-08-12  expires: never       usage: A   
+  [ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
+  [ultimate] (2)  NIIBE Yutaka <gniibe@debian.org>
+
+The sub key is now on the Token.
 
 Lastly, I save changes of **keys on PC** and quit GnuPG. ::
 
index 278d16d..66027e1 100644 (file)
@@ -22,41 +22,40 @@ Besides, some people sometimes prefer the word "passphrase" to
 same thing and it just refer user-password or admin-password.
 
 
-Set up PW1, PW3 and reset code
-==============================
+Set up PW1 and PW3
+==================
 
 Invoke GnuPG with the option ``--card-edit``.  ::
 
-  $ gpg --card-edit
-  Application ID ...: D276000124010200F517000000010000
+  Reader ...........: 234B:0000:FSIJ-1.2.0-87193059:0
+  Application ID ...: D276000124010200FFFE871930590000
   Version ..........: 2.0
-  Manufacturer .....: FSIJ
-  Serial number ....: 00000001
+  Manufacturer .....: unmanaged S/N range
+  Serial number ....: 87193059
   Name of cardholder: Yutaka Niibe
   Language prefs ...: ja
   Sex ..............: male
-  URL of public key : http://www.gniibe.org/gniibe.asc
+  URL of public key : http://www.gniibe.org/gniibe-20150813.asc
   Login data .......: gniibe
   Signature PIN ....: not forced
-  Key attributes ...: 2048R 2048R 2048R
+  Key attributes ...: ed25519 cv25519 ed25519
   Max. PIN lengths .: 127 127 127
   PIN retry counter : 3 3 3
   Signature counter : 0
-  Signature key ....: 1241 24BD 3B48 62AF 7A0A  42F1 00B4 5EBD 4CA7 BABE
-        created ....: 2010-10-15 06:46:33
-  Encryption key....: 42E1 E805 4E6F 1F30 26F2  DC79 79A7 9093 0842 39CF
-        created ....: 2010-10-15 06:46:33
-  Authentication key: B4D9 7142 C42D 6802 F5F7  4E70 9C33 B6BA 5BB0 65DC
-        created ....: 2010-10-22 06:06:36
-  General key info..: 
-  pub  2048R/4CA7BABE 2010-10-15 NIIBE Yutaka <gniibe@fsij.org>
-  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
-
+  Signature key ....: 249C B377 1750 745D 5CDD  323C E267 B052 364F 028D
+        created ....: 2015-08-12 07:10:48
+  Encryption key....: E228 AB42 0F73 3B1D 712D  E50C 850A F040 D619 F240
+        created ....: 2015-08-12 07:10:48
+  Authentication key: E63F 31E6 F203 20B5 D796  D266 5F91 0521 FAA8 05B1
+        created ....: 2015-08-12 07:16:14
+  General key info..: pub  ed25519/E267B052364F028D 2015-08-12 NIIBE Yutaka <gniibe@fsij.org>
+  sec>  ed25519/E267B052364F028D  created: 2015-08-12  expires: never     
+                                  card-no: FFFE 87193059
+  ssb>  cv25519/850AF040D619F240  created: 2015-08-12  expires: never     
+                                  card-no: FFFE 87193059
+  ssb>  ed25519/5F910521FAA805B1  created: 2015-08-12  expires: never     
+                                  card-no: FFFE 87193059
+  
   gpg/card> 
 
 It shows the status of the card (as same as the output of ``gpg --card-status``).
@@ -71,7 +70,7 @@ Note that *the length of PIN should be more than (or equals to) 8* for
 "admin less mode".  ::
 
   gpg/card> passwd
-  gpg: OpenPGP card no. D276000124010200F517000000010000 detected
+  gpg: OpenPGP card no. D276000124010200FFFE871930590000 detected
   
   Please enter the PIN
   Enter PIN: 123456
@@ -94,15 +93,24 @@ please change admin-password at first.
 Then, the token works as same as OpenPGPcard specification
 with regards to PW1 and PW3.)
 
-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. ::
+
+Set up of reset code (optional)
+===============================
+
+Lastly, we can setup reset code, entering admin mode.
+
+Having reset code, we can unblock the token when the token will be blocked
+(by wrong attempts to entering passphrase).  Note that this is optional step.
+
+When reset code is known to someone, that person can try to guess your passphrase of PW1 more times by unblocking the token.  So, I don't use this feature by myself.
+
+If we do, here is the interaction. ::
 
   gpg/card> admin
   Admin commands are allowed
   
   gpg/card> passwd
-  gpg: OpenPGP card no. D276000124010200F517000000010000 detected
+  gpg: OpenPGP card no. D276000124010200FFFE871930590000 detected
   
   1 - change PIN
   2 - unblock PIN
@@ -135,4 +143,4 @@ Then, I quit. ::
 
   gpg/card> quit
 
-That's all.
+That's all in this step.
index 73d5512..43117db 100644 (file)
@@ -9,17 +9,19 @@ Personalize your Gnuk Token
 Invoke GnuPG with the option ``--card-edit``.  ::
 
   $ gpg --card-edit
-  Application ID ...: D276000124010200FFFE330069060000
+
+  Reader ...........: 234B:0000:FSIJ-1.2.0-87193059:0
+  Application ID ...: D276000124010200FFFE871930590000
   Version ..........: 2.0
   Manufacturer .....: unmanaged S/N range
-  Serial number ....: 33006906
+  Serial number ....: 87193059
   Name of cardholder: [not set]
   Language prefs ...: [not set]
   Sex ..............: unspecified
   URL of public key : [not set]
   Login data .......: [not set]
   Signature PIN ....: forced
-  Key attributes ...: 2048R 2048R 2048R
+  Key attributes ...: rsa2048 rsa2048 rsa2048
   Max. PIN lengths .: 127 127 127
   PIN retry counter : 3 3 3
   Signature counter : 0
@@ -58,7 +60,7 @@ login, and URL.  URL specifies the place where I put my public keys. ::
   Sex ((M)ale, (F)emale or space): m
   
   gpg/card> url
-  URL to retrieve public key: http://www.gniibe.org/gniibe.asc
+  URL to retrieve public key: http://www.gniibe.org/gniibe-20150813.asc
   
   gpg/card> login
   Login data (account name): gniibe
@@ -72,4 +74,4 @@ Then, I quit. ::
   
   gpg/card> quit
 
-That's all.
+That's all in this step.
index 430570b..3a690eb 100644 (file)
@@ -27,19 +27,15 @@ Make sure there is no ``scdaemon`` for configuring Gnuk Token.  You can  kill ``
 Serial Number (optional)
 ========================
 
+Note that this is completely optional step.  I don't know anyone other than me, do this.  Even for me, I only do that for a single device among multiple devices I use.  I do that to test the feature.
+
 In the file ``GNUK_SERIAL_NUMBER``, 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.
 
 The tool ``../tool/gnuk_put_binary_libusb.py`` examines  environment variable of ``EMAIL``, and writes corresponding serial number to Gnuk Token. ::
 
   $ ../tool/gnuk_put_binary_libusb.py -s ../GNUK_SERIAL_NUMBER 
   Writing serial number
-  Device:  006
+  Device:  
   Configuration:  1
   Interface:  0
   d2 76 00 01 24 01 02 00 f5 17 00 00 00 01 00 00
-
-
-The example above is the case of libusb version.
-
-Use the tool ``../tool/gnuk_put_binary.py`` instead , for PC/SC Lite.
-You need PyScard for this.
index 57ab153..aa1f78d 100644 (file)
@@ -12,35 +12,38 @@ Here is my GnuPG settings.
 I create ``.gnupg/gpg.conf`` file with the following content. ::
 
   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 0xE267B052364F028D
 
-  default-key 0x4ca7babe
-
-In addition to the ``use-agent`` option, set preferences on algorithms, and specify my default key.
+In addition to the ``use-agent`` option, I specify my default key.
 
 The ``use-agent`` option is for GnuPG 1.4.x and it means using gpg-agent if available.
 If no option, GnuPG 1.4.x directly connects to Gnuk Token by itself, instead of through scdaemon.  When GnuPG 1.4.x tries to access Gnuk Token and scdaemon is running, there are conflicts.
 
 We recommend to specify the ``use-agent`` option for GnuPG 1.4.x to access Gnuk Token through gpg-agent and scdaemon.
 
-For GnuPG 2.0.x, gpg-agent is always used, so there is no need to specify the ``use-agent`` option, but having this option is no harm, anyway.
+For GnuPG 2.0 and 2.1, gpg-agent is always used, so, there is no need to specify the ``use-agent`` option, but having this option is no harm, anyway.
 
 
 Let gpg-agent manage SSH key
 ============================
 
-I deactivate seahorse-agent.  Also, for GNOME 2, I deactivate gnome-keyring managing SSH key. ::
+I create ``.gnupg/gpg-agent.conf`` file with the following content. ::
 
-  $ gconftool-2 --type bool --set /apps/gnome-keyring/daemon-components/ssh false
+  enable-ssh-support
 
-I edit the file /etc/X11/Xsession.options and comment out use-ssh-agent line.
+I edit the file /etc/X11/Xsession.options and comment out use-ssh-agent line,
+so that Xsession doesn't invoke original ssh-agent.  We use gpg-agent as ssh-agent.
 
-Then, I create ``.gnupg/gpg-agent.conf`` file with the following content. ::
+In the files /etc/xdg/autostart/gnome-keyring-ssh.desktop,
+I have a line something like: ::
 
-  enable-ssh-support
+    OnlyShowIn=GNOME;Unity;MATE;
+
+I edit this line to: ::
+
+    OnlyShowIn=
 
+So that no desktop environment enables gnome-keyring for ssh.
 
 References
 ==========
index c872bac..df82038 100644 (file)
@@ -2,8 +2,8 @@
    sphinx-quickstart on Wed Jul  4 15:29:05 2012.
    You can adapt this file completely to your liking, but it should at least
    contain the root `toctree` directive.
-   Copyright (C) 2012, 2013  NIIBE Yutaka
-   Copyright (C) 2012, 2013  Free Software Initiative of Japan
+   Copyright (C) 2012, 2013, 2016  NIIBE Yutaka
+   Copyright (C) 2012, 2013, 2016  Free Software Initiative of Japan
    This document is licensed under a CC-BY-SA 3.0 Unported License
 
 Gnuk Documentation
@@ -20,12 +20,11 @@ Contents:
    udev-rules.rst
    gnuk-token-initial-configuration.rst
    gnuk-personalization.rst
-   generating-2048-RSA-key.rst
+   generating-key.rst
    gnuk-keytocard.rst
    gnuk-keytocard-noremoval.rst
    gnuk-passphrase-setting.rst
    using-gnuk-token-with-another-computer.rst
-   gnome3-gpg-settings.rst
    development.rst
 
 
index 0bae5c8..21b19e5 100644 (file)
@@ -9,6 +9,8 @@ Gnuk is an implementation of USB cryptographic token for GNU Privacy
 Guard.  Gnuk supports OpenPGP card protocol version 2, and it runs on
 STM32F103 processor.
 
+This document explains about Gnuk 1.2, which comes with ECC algorithm.
+
 
 Cryptographic token and feature of Gnuk
 ---------------------------------------
@@ -31,15 +33,15 @@ Target boards for running Gnuk
 ------------------------------
 
 Hardware requirement for Gnuk is the micro controller STM32F103.
-In version 1.1.x, Gnuk supports following boards.
+In version 1.2, Gnuk supports following boards.
 
 * FST-01 (Flying Stone Tiny ZERO-ONE)
 
 * Olimex STM32-H103
 
-* STM32 part of STM8S Discovery Kit
+* ST Nucleo F103
 
-* STBee
+* Nitrokey Start
 
 
 Host prerequisites for using Gnuk Token
@@ -49,11 +51,9 @@ Host prerequisites for using Gnuk Token
 
 * libusb
 
-* [Optional] PC/SC lite (pcscd, libccid)
-
 * [Optional] SSH: openssh
 
-* [optional] Web: scute, firefox
+* [experimental] Web: scute, firefox
 
 
 Usages
@@ -62,4 +62,4 @@ Usages
 * Sign with GnuPG
 * Decrypt with GnuPG
 * Use with OpenSSH through gpg-agent (as ssh-agent)
-* Use with Firefox through Scute for X.509 client certificate authentication
+* [experimental] Use with Firefox through Scute for X.509 client certificate authentication
index 0c26a85..fdd52a0 100644 (file)
@@ -28,10 +28,16 @@ To stop SCDAEMON and let it exit, type::
 Then, you can confirm that there is no SCDAEMON any more by ``ps``
 command.
 
+Or, you can use ``gpgconf`` command.  Type::
+
+       $ gpgconf --reload scdameon
+
+will do the samething.
+
 
 Let GPG-AGENT/SCDAEMON learn
 ============================
 
-To let gpg-agent/scdaemon learn from Gnuk Token, type::
+To let gpg-agent/scdaemon "learn" from Gnuk Token, type::
 
        $ gpg-connect-agent learn /bye
index fae4873..53541bd 100644 (file)
@@ -10,10 +10,13 @@ PC/SC Lite, as it has its own device configuration.
 udev rules for Gnuk Token
 =========================
 
-In case of Debian, there is a file /lib/udev/rules.d/60-gnupg.rules,
-when you install "gnupg" package.  This is the place we need to
-change, if your installation is older (than jessie).  Newer "gnupg"
-package (1.4.15-1 or later) has already supported Gnuk Token.
+In case of Debian, there is a file /lib/udev/rules.d/60-gnupg.rules
+(or /lib/udev/rules.d/60-scdamon.rules for newer version),
+when you install "gnupg" package (or "scdaemon" package).
+This is the place we need to
+change, if your installation is older than jessie.  Newer "gnupg"
+package (1.4.15-1 or later) or "scdaemon" package has already
+supported Gnuk Token.
 
 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
@@ -30,7 +33,7 @@ FSIJ)::
     +
      LABEL="gnupg_rules_end"
 
-When we install "gnupg2" package only (with no "gnupg" package),
+When we only install "gnupg2" package for 2.0 (with no "gnupg" 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::
 
index d33eaa4..6a4a4b6 100644 (file)
@@ -12,90 +12,90 @@ while ``.gnupg`` directory contains keyrings and trustdb, too.
 Fetch the public key and connect it to the Token
 ================================================
 
-Using the Token, we need to put the public key and the secret
-key reference (to the token) in ``.gnupg``.
+In order to use the Token, we need to put the public key and the secret
+key references (to the token) under ``.gnupg`` directory.
 
 To do that, invoke GnuPG with ``--card-edit`` option. ::
 
-  $ gpg --card-edit
-  Application ID ...: D276000124010200F517000000010000
+  Reader ...........: 234B:0000:FSIJ-1.2.0-87193059:0
+  Application ID ...: D276000124010200FFFE871930590000
   Version ..........: 2.0
-  Manufacturer .....: FSIJ
-  Serial number ....: 00000001
+  Manufacturer .....: unmanaged S/N range
+  Serial number ....: 87193059
   Name of cardholder: Yutaka Niibe
   Language prefs ...: ja
   Sex ..............: male
-  URL of public key : http://www.gniibe.org/gniibe.asc
+  URL of public key : http://www.gniibe.org/gniibe-20150813.asc
   Login data .......: gniibe
   Signature PIN ....: not forced
-  Key attributes ...: 2048R 2048R 2048R
+  Key attributes ...: ed25519 cv25519 ed25519
   Max. PIN lengths .: 127 127 127
   PIN retry counter : 3 3 3
-  Signature counter : 6
-  Signature key ....: 1241 24BD 3B48 62AF 7A0A  42F1 00B4 5EBD 4CA7 BABE
-        created ....: 2010-10-15 06:46:33
-  Encryption key....: 42E1 E805 4E6F 1F30 26F2  DC79 79A7 9093 0842 39CF
-        created ....: 2010-10-15 06:46:33
-  Authentication key: B4D9 7142 C42D 6802 F5F7  4E70 9C33 B6BA 5BB0 65DC
-        created ....: 2010-10-22 06:06:36
+  Signature counter : 0
+  Signature key ....: 249C B377 1750 745D 5CDD  323C E267 B052 364F 028D
+        created ....: 2015-08-12 07:10:48
+  Encryption key....: E228 AB42 0F73 3B1D 712D  E50C 850A F040 D619 F240
+        created ....: 2015-08-12 07:10:48
+  Authentication key: E63F 31E6 F203 20B5 D796  D266 5F91 0521 FAA8 05B1
+        created ....: 2015-08-12 07:16:14
   General key info..: [none]
   
   gpg/card> 
 
-It says, there is no key info related to this token on your PC (``[none]``).
+Here, the secret key references (to the token) are created under ``.gnupg/private-keys-v1.d`` directory.  It can be also created when I do ``--card-status`` by GnuPG.
 
-Fetch the public key from URL specified in the Token. ::
+Still, it says that there is no key info related to this token on my PC (``[none]`` for General key info), because I don't have the public key on this PC yet.
+
+So, I fetch the public key from URL specified in the Token. ::
 
   gpg/card> fetch
-  gpg: requesting key 4CA7BABE from http server www.gniibe.org
-  gpg: key 4CA7BABE: public key "NIIBE Yutaka <gniibe@fsij.org>" imported
-  gpg: no ultimately trusted keys found
+  gpg: requesting key E267B052364F028D from http server www.gniibe.org
+  gpg: key E267B052364F028D: public key "NIIBE Yutaka <gniibe@fsij.org>" imported
   gpg: Total number processed: 1
-  gpg:               imported: 1  (RSA: 1)
+  gpg:               imported: 1
+  gpg: marginals needed: 3  completes needed: 1  trust model: pgp
+  gpg: depth: 0  valid:   6  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 6u
   
   gpg/card> 
 
-Good.  The public key is now in ``.gnupg``.  We can examine by ``gpg --list-keys``.
-
-However, the secret key reference (to the token) is not in ``.gnupg`` yet.
+Good.  The public key is now under ``.gnupg`` directory.  We can examine by ``gpg --list-keys``.
 
-It will be generated when I do ``--card-status`` by GnuPG with
-correspoinding public key in ``.gnupg``, or just type return
-at the ``gpg/card>`` prompt. ::
+When I type return at the ``gpg/card>`` prompt, now, I can see: ::
 
-  gpg/card> 
-  
-  Application ID ...: D276000124010200F517000000010000
+  Reader ...........: 234B:0000:FSIJ-1.2.0-87193059:0
+  Application ID ...: D276000124010200FFFE871930590000
   Version ..........: 2.0
-  Manufacturer .....: FSIJ
-  Serial number ....: 00000001
+  Manufacturer .....: unmanaged S/N range
+  Serial number ....: 87193059
   Name of cardholder: Yutaka Niibe
   Language prefs ...: ja
   Sex ..............: male
-  URL of public key : http://www.gniibe.org/gniibe.asc
+  URL of public key : http://www.gniibe.org/gniibe-20150813.asc
   Login data .......: gniibe
   Signature PIN ....: not forced
-  Key attributes ...: 2048R 2048R 2048R
+  Key attributes ...: ed25519 cv25519 ed25519
   Max. PIN lengths .: 127 127 127
   PIN retry counter : 3 3 3
-  Signature counter : 6
-  Signature key ....: 1241 24BD 3B48 62AF 7A0A  42F1 00B4 5EBD 4CA7 BABE
-        created ....: 2010-10-15 06:46:33
-  Encryption key....: 42E1 E805 4E6F 1F30 26F2  DC79 79A7 9093 0842 39CF
-        created ....: 2010-10-15 06:46:33
-  Authentication key: B4D9 7142 C42D 6802 F5F7  4E70 9C33 B6BA 5BB0 65DC
-        created ....: 2010-10-22 06:06:36
-  General key info..: 
-  pub  2048R/4CA7BABE 2010-10-15 NIIBE Yutaka <gniibe@fsij.org>
-  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
-  
+  Signature counter : 0
+  Signature key ....: 249C B377 1750 745D 5CDD  323C E267 B052 364F 028D
+        created ....: 2015-08-12 07:10:48
+  Encryption key....: E228 AB42 0F73 3B1D 712D  E50C 850A F040 D619 F240
+        created ....: 2015-08-12 07:10:48
+  Authentication key: E63F 31E6 F203 20B5 D796  D266 5F91 0521 FAA8 05B1
+        created ....: 2015-08-12 07:16:14
+  General key info..: pub  ed25519/E267B052364F028D 2015-08-12 NIIBE Yutaka <gniibe@fsij.org>
+  sec>  ed25519/E267B052364F028D  created: 2015-08-12  expires: never     
+                                  card-no: FFFE 87193059
+  ssb>  cv25519/850AF040D619F240  created: 2015-08-12  expires: never     
+                                  card-no: FFFE 87193059
+  ssb>  ed25519/5F910521FAA805B1  created: 2015-08-12  expires: never     
+                                  card-no: FFFE 87193059
+
+    
   gpg/card> 
 
+Note that, it displays the information about "General key info".
+
 OK, now I can use the Token on this computer.
 
 
@@ -103,33 +103,43 @@ Update trustdb for the key on Gnuk Token
 ========================================
 
 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.
+key references to the card.  More, I need to update the trustdb.
 
-To do that I do: ::
+To do that, I do: ::
 
-  $ gpg --edit-key 4ca7babe
-  gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc.
+  $ ./gpg --edit-key E267B052364F028D
+  gpg (GnuPG) 2.1.13; Copyright (C) 2016 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: unknown       validity: unknown
-  sub  2048R/084239CF  created: 2010-10-15  expires: never       usage: E   
-  sub  2048R/5BB065DC  created: 2010-10-22  expires: never       usage: A   
+  sec  ed25519/E267B052364F028D
+       created: 2015-08-12  expires: never       usage: SC  
+       card-no: FFFE 87193059
+       trust: unknown       validity: unknown
+  ssb  cv25519/850AF040D619F240
+       created: 2015-08-12  expires: never       usage: E   
+       card-no: FFFE 87193059
+  ssb  ed25519/5F910521FAA805B1
+       created: 2015-08-12  expires: never       usage: A   
+       card-no: FFFE 87193059
   [ unknown] (1). NIIBE Yutaka <gniibe@fsij.org>
   [ unknown] (2)  NIIBE Yutaka <gniibe@debian.org>
-  
-  gpg> 
 
-See, the key is ``unknown`` state.  Add trust for that. ::
+See, the key is ``unknown`` state.  Add trust for that, because it's the key under my control. ::
 
   gpg> 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   
-  sub  2048R/5BB065DC  created: 2010-10-22  expires: never       usage: A   
+  sec  ed25519/E267B052364F028D
+       created: 2015-08-12  expires: never       usage: SC  
+       card-no: FFFE 87193059
+       trust: unknown       validity: unknown
+  ssb  cv25519/850AF040D619F240
+       created: 2015-08-12  expires: never       usage: E   
+       card-no: FFFE 87193059
+  ssb  ed25519/5F910521FAA805B1
+       created: 2015-08-12  expires: never       usage: A   
+       card-no: FFFE 87193059
   [ unknown] (1). NIIBE Yutaka <gniibe@fsij.org>
   [ unknown] (2)  NIIBE Yutaka <gniibe@debian.org>
   
@@ -146,32 +156,49 @@ See, the key is ``unknown`` state.  Add trust for that. ::
   Your decision? 5
   Do you really want to set this key to ultimate trust? (y/N) y
   
-  pub  2048R/4CA7BABE  created: 2010-10-15  expires: never       usage: SC  
-                       trust: ultimate      validity: unknown
-  sub  2048R/084239CF  created: 2010-10-15  expires: never       usage: E   
-  sub  2048R/5BB065DC  created: 2010-10-22  expires: never       usage: A   
+  sec  ed25519/E267B052364F028D
+       created: 2015-08-12  expires: never       usage: SC  
+       card-no: FFFE 87193059
+       trust: ultimate      validity: unknown
+  ssb  cv25519/850AF040D619F240
+       created: 2015-08-12  expires: never       usage: E   
+       card-no: FFFE 87193059
+  ssb  ed25519/5F910521FAA805B1
+       created: 2015-08-12  expires: never       usage: A   
+       card-no: FFFE 87193059
   [ unknown] (1). NIIBE Yutaka <gniibe@fsij.org>
   [ unknown] (2)  NIIBE Yutaka <gniibe@debian.org>
   Please note that the shown key validity is not necessarily correct
   unless you restart the program.
   
-  $ 
+  gpg> 
 
-Next time I invoke GnuPG, it will be ``ultimate`` key.  Let's see: ::
+And I quit from gpg.  Then, when I invoke GnuPG, it will be ``ultimate`` key.  Let's see: ::
 
-  $ gpg --edit-key 4ca7babe
-  gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc.
+  $ ./gpg --edit-key E267B052364F028D
+  gpg (GnuPG) 2.1.13; Copyright (C) 2016 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   
+
+  gpg: checking the trustdb
+  gpg: marginals needed: 3  completes needed: 1  trust model: pgp
+  gpg: depth: 0  valid:   7  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 7u
+  sec  ed25519/E267B052364F028D
+       created: 2015-08-12  expires: never       usage: SC  
+       card-no: FFFE 87193059
+       trust: ultimate      validity: ultimate
+  ssb  cv25519/850AF040D619F240
+       created: 2015-08-12  expires: never       usage: E   
+       card-no: FFFE 87193059
+  ssb  ed25519/5F910521FAA805B1
+       created: 2015-08-12  expires: never       usage: A   
+       card-no: FFFE 87193059
   [ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
   [ultimate] (2)  NIIBE Yutaka <gniibe@debian.org>
-  
+
   gpg> quit
-  $ 
+  $
+
+OK, all set.  I'm ready to use my Gnuk Token on this PC.
index 967e36c..0b79414 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Sphinx stylesheet -- basic theme.
  *
- * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
+ * :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
  * :license: BSD, see LICENSE for details.
  *
  */
@@ -52,6 +52,8 @@ div.sphinxsidebar {
     width: 230px;
     margin-left: -100%;
     font-size: 90%;
+    word-wrap: break-word;
+    overflow-wrap : break-word;
 }
 
 div.sphinxsidebar ul {
@@ -83,10 +85,6 @@ div.sphinxsidebar #searchbox input[type="text"] {
     width: 170px;
 }
 
-div.sphinxsidebar #searchbox input[type="submit"] {
-    width: 30px;
-}
-
 img {
     border: 0;
     max-width: 100%;
@@ -187,6 +185,13 @@ div.genindex-jumpbox {
 
 /* -- general body styles --------------------------------------------------- */
 
+div.body p, div.body dd, div.body li, div.body blockquote {
+    -moz-hyphens: auto;
+    -ms-hyphens: auto;
+    -webkit-hyphens: auto;
+    hyphens: auto;
+}
+
 a.headerlink {
     visibility: hidden;
 }
@@ -197,7 +202,10 @@ h3:hover > a.headerlink,
 h4:hover > a.headerlink,
 h5:hover > a.headerlink,
 h6:hover > a.headerlink,
-dt:hover > a.headerlink {
+dt:hover > a.headerlink,
+caption:hover > a.headerlink,
+p.caption:hover > a.headerlink,
+div.code-block-caption:hover > a.headerlink {
     visibility: visible;
 }
 
@@ -314,6 +322,13 @@ table.docutils {
     border-collapse: collapse;
 }
 
+table caption span.caption-number {
+    font-style: italic;
+}
+
+table caption span.caption-text {
+}
+
 table.docutils td, table.docutils th {
     padding: 1px 8px 1px 5px;
     border-top: 0;
@@ -344,6 +359,25 @@ table.citation td {
     border-bottom: none;
 }
 
+/* -- figures --------------------------------------------------------------- */
+
+div.figure {
+    margin: 0.5em;
+    padding: 0.5em;
+}
+
+div.figure p.caption {
+    padding: 0.3em;
+}
+
+div.figure p.caption span.caption-number {
+    font-style: italic;
+}
+
+div.figure p.caption span.caption-text {
+}
+
+
 /* -- other body styles ----------------------------------------------------- */
 
 ol.arabic {
@@ -406,6 +440,10 @@ dl.glossary dt {
     font-size: 1.3em;
 }
 
+.sig-paren {
+    font-size: larger;
+}
+
 .versionmodified {
     font-style: italic;
 }
@@ -456,6 +494,13 @@ pre {
     overflow-y: hidden;  /* fixes display issues on Chrome browsers */
 }
 
+span.pre {
+    -moz-hyphens: none;
+    -ms-hyphens: none;
+    -webkit-hyphens: none;
+    hyphens: none;
+}
+
 td.linenos pre {
     padding: 5px 0px;
     border: 0;
@@ -471,22 +516,51 @@ table.highlighttable td {
     padding: 0 0.5em 0 0.5em;
 }
 
-tt.descname {
+div.code-block-caption {
+    padding: 2px 5px;
+    font-size: small;
+}
+
+div.code-block-caption code {
+    background-color: transparent;
+}
+
+div.code-block-caption + div > div.highlight > pre {
+    margin-top: 0;
+}
+
+div.code-block-caption span.caption-number {
+    padding: 0.1em 0.3em;
+    font-style: italic;
+}
+
+div.code-block-caption span.caption-text {
+}
+
+div.literal-block-wrapper {
+    padding: 1em 1em 0;
+}
+
+div.literal-block-wrapper div.highlight {
+    margin: 0;
+}
+
+code.descname {
     background-color: transparent;
     font-weight: bold;
     font-size: 1.2em;
 }
 
-tt.descclassname {
+code.descclassname {
     background-color: transparent;
 }
 
-tt.xref, a tt {
+code.xref, a code {
     background-color: transparent;
     font-weight: bold;
 }
 
-h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
+h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
     background-color: transparent;
 }
 
diff --git a/doc-gnuk/_static/classic.css b/doc-gnuk/_static/classic.css
new file mode 100644 (file)
index 0000000..d98894b
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * default.css_t
+ * ~~~~~~~~~~~~~
+ *
+ * Sphinx stylesheet -- default theme.
+ *
+ * :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+@import url("basic.css");
+
+/* -- page layout ----------------------------------------------------------- */
+
+body {
+    font-family: sans-serif;
+    font-size: 100%;
+    background-color: #11303d;
+    color: #000;
+    margin: 0;
+    padding: 0;
+}
+
+div.document {
+    background-color: #1c4e63;
+}
+
+div.documentwrapper {
+    float: left;
+    width: 100%;
+}
+
+div.bodywrapper {
+    margin: 0 0 0 230px;
+}
+
+div.body {
+    background-color: #ffffff;
+    color: #000000;
+    padding: 0 20px 30px 20px;
+}
+
+div.footer {
+    color: #ffffff;
+    width: 100%;
+    padding: 9px 0 9px 0;
+    text-align: center;
+    font-size: 75%;
+}
+
+div.footer a {
+    color: #ffffff;
+    text-decoration: underline;
+}
+
+div.related {
+    background-color: #133f52;
+    line-height: 30px;
+    color: #ffffff;
+}
+
+div.related a {
+    color: #ffffff;
+}
+
+div.sphinxsidebar {
+}
+
+div.sphinxsidebar h3 {
+    font-family: 'Trebuchet MS', sans-serif;
+    color: #ffffff;
+    font-size: 1.4em;
+    font-weight: normal;
+    margin: 0;
+    padding: 0;
+}
+
+div.sphinxsidebar h3 a {
+    color: #ffffff;
+}
+
+div.sphinxsidebar h4 {
+    font-family: 'Trebuchet MS', sans-serif;
+    color: #ffffff;
+    font-size: 1.3em;
+    font-weight: normal;
+    margin: 5px 0 0 0;
+    padding: 0;
+}
+
+div.sphinxsidebar p {
+    color: #ffffff;
+}
+
+div.sphinxsidebar p.topless {
+    margin: 5px 10px 10px 10px;
+}
+
+div.sphinxsidebar ul {
+    margin: 10px;
+    padding: 0;
+    color: #ffffff;
+}
+
+div.sphinxsidebar a {
+    color: #98dbcc;
+}
+
+div.sphinxsidebar input {
+    border: 1px solid #98dbcc;
+    font-family: sans-serif;
+    font-size: 1em;
+}
+
+
+
+/* -- hyperlink styles ------------------------------------------------------ */
+
+a {
+    color: #355f7c;
+    text-decoration: none;
+}
+
+a:visited {
+    color: #355f7c;
+    text-decoration: none;
+}
+
+a:hover {
+    text-decoration: underline;
+}
+
+
+
+/* -- body styles ----------------------------------------------------------- */
+
+div.body h1,
+div.body h2,
+div.body h3,
+div.body h4,
+div.body h5,
+div.body h6 {
+    font-family: 'Trebuchet MS', sans-serif;
+    background-color: #f2f2f2;
+    font-weight: normal;
+    color: #20435c;
+    border-bottom: 1px solid #ccc;
+    margin: 20px -20px 10px -20px;
+    padding: 3px 0 3px 10px;
+}
+
+div.body h1 { margin-top: 0; font-size: 200%; }
+div.body h2 { font-size: 160%; }
+div.body h3 { font-size: 140%; }
+div.body h4 { font-size: 120%; }
+div.body h5 { font-size: 110%; }
+div.body h6 { font-size: 100%; }
+
+a.headerlink {
+    color: #c60f0f;
+    font-size: 0.8em;
+    padding: 0 4px 0 4px;
+    text-decoration: none;
+}
+
+a.headerlink:hover {
+    background-color: #c60f0f;
+    color: white;
+}
+
+div.body p, div.body dd, div.body li, div.body blockquote {
+    text-align: justify;
+    line-height: 130%;
+}
+
+div.admonition p.admonition-title + p {
+    display: inline;
+}
+
+div.admonition p {
+    margin-bottom: 5px;
+}
+
+div.admonition pre {
+    margin-bottom: 5px;
+}
+
+div.admonition ul, div.admonition ol {
+    margin-bottom: 5px;
+}
+
+div.note {
+    background-color: #eee;
+    border: 1px solid #ccc;
+}
+
+div.seealso {
+    background-color: #ffc;
+    border: 1px solid #ff6;
+}
+
+div.topic {
+    background-color: #eee;
+}
+
+div.warning {
+    background-color: #ffe4e4;
+    border: 1px solid #f66;
+}
+
+p.admonition-title {
+    display: inline;
+}
+
+p.admonition-title:after {
+    content: ":";
+}
+
+pre {
+    padding: 5px;
+    background-color: #eeffcc;
+    color: #333333;
+    line-height: 120%;
+    border: 1px solid #ac9;
+    border-left: none;
+    border-right: none;
+}
+
+code {
+    background-color: #ecf0f3;
+    padding: 0 1px 0 1px;
+    font-size: 0.95em;
+}
+
+th {
+    background-color: #ede;
+}
+
+.warning code {
+    background: #efc2c2;
+}
+
+.note code {
+    background: #d6d6d6;
+}
+
+.viewcode-back {
+    font-family: sans-serif;
+}
+
+div.viewcode-block:target {
+    background-color: #f4debf;
+    border-top: 1px solid #ac9;
+    border-bottom: 1px solid #ac9;
+}
+
+div.code-block-caption {
+    color: #efefef;
+    background-color: #1c4e63;
+}
\ No newline at end of file
index 551517b..4a2bf8a 100644 (file)
Binary files a/doc-gnuk/_static/comment-bright.png and b/doc-gnuk/_static/comment-bright.png differ
index 09b54be..5fe0897 100644 (file)
Binary files a/doc-gnuk/_static/comment-close.png and b/doc-gnuk/_static/comment-close.png differ
index 92feb52..e651e98 100644 (file)
Binary files a/doc-gnuk/_static/comment.png and b/doc-gnuk/_static/comment.png differ
index 5f1399a..81b9363 100644 (file)
@@ -1,256 +1 @@
-/*
- * default.css_t
- * ~~~~~~~~~~~~~
- *
- * Sphinx stylesheet -- default theme.
- *
- * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
- * :license: BSD, see LICENSE for details.
- *
- */
-
-@import url("basic.css");
-
-/* -- page layout ----------------------------------------------------------- */
-
-body {
-    font-family: sans-serif;
-    font-size: 100%;
-    background-color: #11303d;
-    color: #000;
-    margin: 0;
-    padding: 0;
-}
-
-div.document {
-    background-color: #1c4e63;
-}
-
-div.documentwrapper {
-    float: left;
-    width: 100%;
-}
-
-div.bodywrapper {
-    margin: 0 0 0 230px;
-}
-
-div.body {
-    background-color: #ffffff;
-    color: #000000;
-    padding: 0 20px 30px 20px;
-}
-
-div.footer {
-    color: #ffffff;
-    width: 100%;
-    padding: 9px 0 9px 0;
-    text-align: center;
-    font-size: 75%;
-}
-
-div.footer a {
-    color: #ffffff;
-    text-decoration: underline;
-}
-
-div.related {
-    background-color: #133f52;
-    line-height: 30px;
-    color: #ffffff;
-}
-
-div.related a {
-    color: #ffffff;
-}
-
-div.sphinxsidebar {
-}
-
-div.sphinxsidebar h3 {
-    font-family: 'Trebuchet MS', sans-serif;
-    color: #ffffff;
-    font-size: 1.4em;
-    font-weight: normal;
-    margin: 0;
-    padding: 0;
-}
-
-div.sphinxsidebar h3 a {
-    color: #ffffff;
-}
-
-div.sphinxsidebar h4 {
-    font-family: 'Trebuchet MS', sans-serif;
-    color: #ffffff;
-    font-size: 1.3em;
-    font-weight: normal;
-    margin: 5px 0 0 0;
-    padding: 0;
-}
-
-div.sphinxsidebar p {
-    color: #ffffff;
-}
-
-div.sphinxsidebar p.topless {
-    margin: 5px 10px 10px 10px;
-}
-
-div.sphinxsidebar ul {
-    margin: 10px;
-    padding: 0;
-    color: #ffffff;
-}
-
-div.sphinxsidebar a {
-    color: #98dbcc;
-}
-
-div.sphinxsidebar input {
-    border: 1px solid #98dbcc;
-    font-family: sans-serif;
-    font-size: 1em;
-}
-
-
-
-/* -- hyperlink styles ------------------------------------------------------ */
-
-a {
-    color: #355f7c;
-    text-decoration: none;
-}
-
-a:visited {
-    color: #355f7c;
-    text-decoration: none;
-}
-
-a:hover {
-    text-decoration: underline;
-}
-
-
-
-/* -- body styles ----------------------------------------------------------- */
-
-div.body h1,
-div.body h2,
-div.body h3,
-div.body h4,
-div.body h5,
-div.body h6 {
-    font-family: 'Trebuchet MS', sans-serif;
-    background-color: #f2f2f2;
-    font-weight: normal;
-    color: #20435c;
-    border-bottom: 1px solid #ccc;
-    margin: 20px -20px 10px -20px;
-    padding: 3px 0 3px 10px;
-}
-
-div.body h1 { margin-top: 0; font-size: 200%; }
-div.body h2 { font-size: 160%; }
-div.body h3 { font-size: 140%; }
-div.body h4 { font-size: 120%; }
-div.body h5 { font-size: 110%; }
-div.body h6 { font-size: 100%; }
-
-a.headerlink {
-    color: #c60f0f;
-    font-size: 0.8em;
-    padding: 0 4px 0 4px;
-    text-decoration: none;
-}
-
-a.headerlink:hover {
-    background-color: #c60f0f;
-    color: white;
-}
-
-div.body p, div.body dd, div.body li {
-    text-align: justify;
-    line-height: 130%;
-}
-
-div.admonition p.admonition-title + p {
-    display: inline;
-}
-
-div.admonition p {
-    margin-bottom: 5px;
-}
-
-div.admonition pre {
-    margin-bottom: 5px;
-}
-
-div.admonition ul, div.admonition ol {
-    margin-bottom: 5px;
-}
-
-div.note {
-    background-color: #eee;
-    border: 1px solid #ccc;
-}
-
-div.seealso {
-    background-color: #ffc;
-    border: 1px solid #ff6;
-}
-
-div.topic {
-    background-color: #eee;
-}
-
-div.warning {
-    background-color: #ffe4e4;
-    border: 1px solid #f66;
-}
-
-p.admonition-title {
-    display: inline;
-}
-
-p.admonition-title:after {
-    content: ":";
-}
-
-pre {
-    padding: 5px;
-    background-color: #eeffcc;
-    color: #333333;
-    line-height: 120%;
-    border: 1px solid #ac9;
-    border-left: none;
-    border-right: none;
-}
-
-tt {
-    background-color: #ecf0f3;
-    padding: 0 1px 0 1px;
-    font-size: 0.95em;
-}
-
-th {
-    background-color: #ede;
-}
-
-.warning tt {
-    background: #efc2c2;
-}
-
-.note tt {
-    background: #d6d6d6;
-}
-
-.viewcode-back {
-    font-family: sans-serif;
-}
-
-div.viewcode-block:target {
-    background-color: #f4debf;
-    border-top: 1px solid #ac9;
-    border-bottom: 1px solid #ac9;
-}
\ No newline at end of file
+@import url("classic.css");
index c5455c9..8163495 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Sphinx JavaScript utilities for all documentation.
  *
- * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
+ * :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
  * :license: BSD, see LICENSE for details.
  *
  */
@@ -91,6 +91,30 @@ jQuery.fn.highlightText = function(text, className) {
   });
 };
 
+/*
+ * backward compatibility for jQuery.browser
+ * This will be supported until firefox bug is fixed.
+ */
+if (!jQuery.browser) {
+  jQuery.uaMatch = function(ua) {
+    ua = ua.toLowerCase();
+
+    var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
+      /(webkit)[ \/]([\w.]+)/.exec(ua) ||
+      /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
+      /(msie) ([\w.]+)/.exec(ua) ||
+      ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
+      [];
+
+    return {
+      browser: match[ 1 ] || "",
+      version: match[ 2 ] || "0"
+    };
+  };
+  jQuery.browser = {};
+  jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
+}
+
 /**
  * Small JavaScript module for the documentation.
  */
@@ -100,6 +124,7 @@ var Documentation = {
     this.fixFirefoxAnchorBug();
     this.highlightSearchWords();
     this.initIndexTable();
+    
   },
 
   /**
@@ -152,9 +177,10 @@ var Documentation = {
 
   /**
    * workaround a firefox stupidity
+   * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075
    */
   fixFirefoxAnchorBug : function() {
-    if (document.location.hash && $.browser.mozilla)
+    if (document.location.hash)
       window.setTimeout(function() {
         document.location.href += '';
       }, 10);
@@ -227,6 +253,29 @@ var Documentation = {
     });
     var url = parts.join('/');
     return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
+  },
+
+  initOnKeyListeners: function() {
+    $(document).keyup(function(event) {
+      var activeElementType = document.activeElement.tagName;
+      // don't navigate when in search box or textarea
+      if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') {
+        switch (event.keyCode) {
+          case 37: // left
+            var prevHref = $('link[rel="prev"]').prop('href');
+            if (prevHref) {
+              window.location.href = prevHref;
+              return false;
+            }
+          case 39: // right
+            var nextHref = $('link[rel="next"]').prop('href');
+            if (nextHref) {
+              window.location.href = nextHref;
+              return false;
+            }
+        }
+      }
+    });
   }
 };
 
@@ -235,4 +284,4 @@ _ = Documentation.gettext;
 
 $(document).ready(function() {
   Documentation.init();
-});
+});
\ No newline at end of file
index 6f7ad78..20cd4e2 100644 (file)
Binary files a/doc-gnuk/_static/down-pressed.png and b/doc-gnuk/_static/down-pressed.png differ
index 3003a88..b440895 100644 (file)
Binary files a/doc-gnuk/_static/down.png and b/doc-gnuk/_static/down.png differ
index d18082e..eedc819 100644 (file)
Binary files a/doc-gnuk/_static/file.png and b/doc-gnuk/_static/file.png differ
index 417eb67..25a72c9 100644 (file)
 /*!
- * jQuery JavaScript Library v1.7.2
- * http://jquery.com/
- *
- * Copyright 2011, John Resig
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
+ * jQuery JavaScript Library v3.1.1
+ * https://jquery.com/
  *
  * Includes Sizzle.js
- * http://sizzlejs.com/
- * Copyright 2011, The Dojo Foundation
- * Released under the MIT, BSD, and GPL Licenses.
+ * https://sizzlejs.com/
  *
- * Date: Fri Aug 29 09:46:34 UTC 2014
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license
+ * https://jquery.org/license
+ *
+ * Date: 2016-12-11T15:18Z
  */
-(function( window, undefined ) {
-
-// Use the correct document accordingly with window argument (sandbox)
-var document = window.document,
-       navigator = window.navigator,
-       location = window.location;
-var jQuery = (function() {
-
-// Define a local copy of jQuery
-var jQuery = function( selector, context ) {
-               // The jQuery object is actually just the init constructor 'enhanced'
-               return new jQuery.fn.init( selector, context, rootjQuery );
-       },
-
-       // Map over jQuery in case of overwrite
-       _jQuery = window.jQuery,
-
-       // Map over the $ in case of overwrite
-       _$ = window.$,
-
-       // A central reference to the root jQuery(document)
-       rootjQuery,
-
-       // A simple way to check for HTML strings or ID strings
-       // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
-       quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
-
-       // Check if a string has a non-whitespace character in it
-       rnotwhite = /\S/,
-
-       // Used for trimming whitespace
-       trimLeft = /^\s+/,
-       trimRight = /\s+$/,
-
-       // Match a standalone tag
-       rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
-
-       // JSON RegExp
-       rvalidchars = /^[\],:{}\s]*$/,
-       rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
-       rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
-       rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
-
-       // Useragent RegExp
-       rwebkit = /(webkit)[ \/]([\w.]+)/,
-       ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
-       rmsie = /(msie) ([\w.]+)/,
-       rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,
+( function( global, factory ) {
+
+       "use strict";
+
+       if ( typeof module === "object" && typeof module.exports === "object" ) {
+
+               // For CommonJS and CommonJS-like environments where a proper `window`
+               // is present, execute the factory and get jQuery.
+               // For environments that do not have a `window` with a `document`
+               // (such as Node.js), expose a factory as module.exports.
+               // This accentuates the need for the creation of a real `window`.
+               // e.g. var jQuery = require("jquery")(window);
+               // See ticket #14549 for more info.
+               module.exports = global.document ?
+                       factory( global, true ) :
+                       function( w ) {
+                               if ( !w.document ) {
+                                       throw new Error( "jQuery requires a window with a document" );
+                               }
+                               return factory( w );
+                       };
+       } else {
+               factory( global );
+       }
 
-       // Matches dashed string for camelizing
-       rdashAlpha = /-([a-z]|[0-9])/ig,
-       rmsPrefix = /^-ms-/,
+// Pass this if window is not defined yet
+} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
 
-       // Used by jQuery.camelCase as callback to replace()
-       fcamelCase = function( all, letter ) {
-               return ( letter + "" ).toUpperCase();
-       },
+// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
+// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
+// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
+// enough that all such attempts are guarded in a try block.
 
-       // Keep a UserAgent string for use with jQuery.browser
-       userAgent = navigator.userAgent,
 
-       // For matching the engine and version of the browser
-       browserMatch,
+var arr = [];
 
-       // The deferred used on DOM ready
-       readyList,
+var document = window.document;
 
-       // The ready event handler
-       DOMContentLoaded,
+var getProto = Object.getPrototypeOf;
 
-       // Save a reference to some core methods
-       toString = Object.prototype.toString,
-       hasOwn = Object.prototype.hasOwnProperty,
-       push = Array.prototype.push,
-       slice = Array.prototype.slice,
-       trim = String.prototype.trim,
-       indexOf = Array.prototype.indexOf,
+var slice = arr.slice;
 
-       // [[Class]] -> type pairs
-       class2type = {};
+var concat = arr.concat;
 
-jQuery.fn = jQuery.prototype = {
-       constructor: jQuery,
-       init: function( selector, context, rootjQuery ) {
-               var match, elem, ret, doc;
+var push = arr.push;
 
-               // Handle $(""), $(null), or $(undefined)
-               if ( !selector ) {
-                       return this;
-               }
+var indexOf = arr.indexOf;
 
-               // Handle $(DOMElement)
-               if ( selector.nodeType ) {
-                       this.context = this[0] = selector;
-                       this.length = 1;
-                       return this;
-               }
+var class2type = {};
 
-               // The body element only exists once, optimize finding it
-               if ( selector === "body" && !context && document.body ) {
-                       this.context = document;
-                       this[0] = document.body;
-                       this.selector = selector;
-                       this.length = 1;
-                       return this;
-               }
+var toString = class2type.toString;
 
-               // Handle HTML strings
-               if ( typeof selector === "string" ) {
-                       // Are we dealing with HTML string or an ID?
-                       if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
-                               // Assume that strings that start and end with <> are HTML and skip the regex check
-                               match = [ null, selector, null ];
+var hasOwn = class2type.hasOwnProperty;
 
-                       } else {
-                               match = quickExpr.exec( selector );
-                       }
+var fnToString = hasOwn.toString;
 
-                       // Verify a match, and that no context was specified for #id
-                       if ( match && (match[1] || !context) ) {
+var ObjectFunctionString = fnToString.call( Object );
 
-                               // HANDLE: $(html) -> $(array)
-                               if ( match[1] ) {
-                                       context = context instanceof jQuery ? context[0] : context;
-                                       doc = ( context ? context.ownerDocument || context : document );
+var support = {};
 
-                                       // If a single string is passed in and it's a single tag
-                                       // just do a createElement and skip the rest
-                                       ret = rsingleTag.exec( selector );
 
-                                       if ( ret ) {
-                                               if ( jQuery.isPlainObject( context ) ) {
-                                                       selector = [ document.createElement( ret[1] ) ];
-                                                       jQuery.fn.attr.call( selector, context, true );
 
-                                               } else {
-                                                       selector = [ doc.createElement( ret[1] ) ];
-                                               }
+       function DOMEval( code, doc ) {
+               doc = doc || document;
 
-                                       } else {
-                                               ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
-                                               selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;
-                                       }
+               var script = doc.createElement( "script" );
 
-                                       return jQuery.merge( this, selector );
+               script.text = code;
+               doc.head.appendChild( script ).parentNode.removeChild( script );
+       }
+/* global Symbol */
+// Defining this global in .eslintrc.json would create a danger of using the global
+// unguarded in another place, it seems safer to define global only for this module
 
-                               // HANDLE: $("#id")
-                               } else {
-                                       elem = document.getElementById( match[2] );
-
-                                       // Check parentNode to catch when Blackberry 4.6 returns
-                                       // nodes that are no longer in the document #6963
-                                       if ( elem && elem.parentNode ) {
-                                               // Handle the case where IE and Opera return items
-                                               // by name instead of ID
-                                               if ( elem.id !== match[2] ) {
-                                                       return rootjQuery.find( selector );
-                                               }
 
-                                               // Otherwise, we inject the element directly into the jQuery object
-                                               this.length = 1;
-                                               this[0] = elem;
-                                       }
 
-                                       this.context = document;
-                                       this.selector = selector;
-                                       return this;
-                               }
+var
+       version = "3.1.1",
 
-                       // HANDLE: $(expr, $(...))
-                       } else if ( !context || context.jquery ) {
-                               return ( context || rootjQuery ).find( selector );
+       // Define a local copy of jQuery
+       jQuery = function( selector, context ) {
 
-                       // HANDLE: $(expr, context)
-                       // (which is just equivalent to: $(context).find(expr)
-                       } else {
-                               return this.constructor( context ).find( selector );
-                       }
+               // The jQuery object is actually just the init constructor 'enhanced'
+               // Need init if jQuery is called (just allow error to be thrown if not included)
+               return new jQuery.fn.init( selector, context );
+       },
 
-               // HANDLE: $(function)
-               // Shortcut for document ready
-               } else if ( jQuery.isFunction( selector ) ) {
-                       return rootjQuery.ready( selector );
-               }
+       // Support: Android <=4.0 only
+       // Make sure we trim BOM and NBSP
+       rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
 
-               if ( selector.selector !== undefined ) {
-                       this.selector = selector.selector;
-                       this.context = selector.context;
-               }
+       // Matches dashed string for camelizing
+       rmsPrefix = /^-ms-/,
+       rdashAlpha = /-([a-z])/g,
 
-               return jQuery.makeArray( selector, this );
-       },
+       // Used by jQuery.camelCase as callback to replace()
+       fcamelCase = function( all, letter ) {
+               return letter.toUpperCase();
+       };
 
-       // Start with an empty selector
-       selector: "",
+jQuery.fn = jQuery.prototype = {
 
        // The current version of jQuery being used
-       jquery: "1.7.2",
+       jquery: version,
+
+       constructor: jQuery,
 
        // The default length of a jQuery object is 0
        length: 0,
 
-       // The number of elements contained in the matched element set
-       size: function() {
-               return this.length;
-       },
-
        toArray: function() {
-               return slice.call( this, 0 );
+               return slice.call( this );
        },
 
        // Get the Nth element in the matched element set OR
        // Get the whole matched element set as a clean array
        get: function( num ) {
-               return num == null ?
 
-                       // Return a 'clean' array
-                       this.toArray() :
+               // Return all the elements in a clean array
+               if ( num == null ) {
+                       return slice.call( this );
+               }
 
-                       // Return just the object
-                       ( num < 0 ? this[ this.length + num ] : this[ num ] );
+               // Return just the one element from the set
+               return num < 0 ? this[ num + this.length ] : this[ num ];
        },
 
        // Take an array of elements and push it onto the stack
        // (returning the new matched element set)
-       pushStack: function( elems, name, selector ) {
-               // Build a new jQuery matched element set
-               var ret = this.constructor();
-
-               if ( jQuery.isArray( elems ) ) {
-                       push.apply( ret, elems );
+       pushStack: function( elems ) {
 
-               } else {
-                       jQuery.merge( ret, elems );
-               }
+               // Build a new jQuery matched element set
+               var ret = jQuery.merge( this.constructor(), elems );
 
                // Add the old object onto the stack (as a reference)
                ret.prevObject = this;
 
-               ret.context = this.context;
-
-               if ( name === "find" ) {
-                       ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
-               } else if ( name ) {
-                       ret.selector = this.selector + "." + name + "(" + selector + ")";
-               }
-
                // Return the newly-formed element set
                return ret;
        },
 
        // Execute a callback for every element in the matched set.
-       // (You can seed the arguments with an array of args, but this is
-       // only used internally.)
-       each: function( callback, args ) {
-               return jQuery.each( this, callback, args );
+       each: function( callback ) {
+               return jQuery.each( this, callback );
        },
 
-       ready: function( fn ) {
-               // Attach the listeners
-               jQuery.bindReady();
-
-               // Add the callback
-               readyList.add( fn );
-
-               return this;
+       map: function( callback ) {
+               return this.pushStack( jQuery.map( this, function( elem, i ) {
+                       return callback.call( elem, i, elem );
+               } ) );
        },
 
-       eq: function( i ) {
-               i = +i;
-               return i === -1 ?
-                       this.slice( i ) :
-                       this.slice( i, i + 1 );
+       slice: function() {
+               return this.pushStack( slice.apply( this, arguments ) );
        },
 
        first: function() {
@@ -296,34 +175,26 @@ jQuery.fn = jQuery.prototype = {
                return this.eq( -1 );
        },
 
-       slice: function() {
-               return this.pushStack( slice.apply( this, arguments ),
-                       "slice", slice.call(arguments).join(",") );
-       },
-
-       map: function( callback ) {
-               return this.pushStack( jQuery.map(this, function( elem, i ) {
-                       return callback.call( elem, i, elem );
-               }));
+       eq: function( i ) {
+               var len = this.length,
+                       j = +i + ( i < 0 ? len : 0 );
+               return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
        },
 
        end: function() {
-               return this.prevObject || this.constructor(null);
+               return this.prevObject || this.constructor();
        },
 
        // For internal use only.
        // Behaves like an Array's method, not like a jQuery method.
        push: push,
-       sort: [].sort,
-       splice: [].splice
+       sort: arr.sort,
+       splice: arr.splice
 };
 
-// Give the init function the jQuery prototype for later instantiation
-jQuery.fn.init.prototype = jQuery.fn;
-
 jQuery.extend = jQuery.fn.extend = function() {
        var options, name, src, copy, copyIsArray, clone,
-               target = arguments[0] || {},
+               target = arguments[ 0 ] || {},
                i = 1,
                length = arguments.length,
                deep = false;
@@ -331,25 +202,28 @@ jQuery.extend = jQuery.fn.extend = function() {
        // Handle a deep copy situation
        if ( typeof target === "boolean" ) {
                deep = target;
-               target = arguments[1] || {};
-               // skip the boolean and the target
-               i = 2;
+
+               // Skip the boolean and the target
+               target = arguments[ i ] || {};
+               i++;
        }
 
        // Handle case when target is a string or something (possible in deep copy)
-       if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+       if ( typeof target !== "object" && !jQuery.isFunction( target ) ) {
                target = {};
        }
 
-       // extend jQuery itself if only one argument is passed
-       if ( length === i ) {
+       // Extend jQuery itself if only one argument is passed
+       if ( i === length ) {
                target = this;
-               --i;
+               i--;
        }
 
        for ( ; i < length; i++ ) {
+
                // Only deal with non-null/undefined values
-               if ( (options = arguments[ i ]) != null ) {
+               if ( ( options = arguments[ i ] ) != null ) {
+
                        // Extend the base object
                        for ( name in options ) {
                                src = target[ name ];
@@ -361,13 +235,15 @@ jQuery.extend = jQuery.fn.extend = function() {
                                }
 
                                // Recurse if we're merging plain objects or arrays
-                               if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+                               if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
+                                       ( copyIsArray = jQuery.isArray( copy ) ) ) ) {
+
                                        if ( copyIsArray ) {
                                                copyIsArray = false;
-                                               clone = src && jQuery.isArray(src) ? src : [];
+                                               clone = src && jQuery.isArray( src ) ? src : [];
 
                                        } else {
-                                               clone = src && jQuery.isPlainObject(src) ? src : {};
+                                               clone = src && jQuery.isPlainObject( src ) ? src : {};
                                        }
 
                                        // Never move original objects, clone them
@@ -385,357 +261,163 @@ jQuery.extend = jQuery.fn.extend = function() {
        return target;
 };
 
-jQuery.extend({
-       noConflict: function( deep ) {
-               if ( window.$ === jQuery ) {
-                       window.$ = _$;
-               }
-
-               if ( deep && window.jQuery === jQuery ) {
-                       window.jQuery = _jQuery;
-               }
-
-               return jQuery;
-       },
-
-       // Is the DOM ready to be used? Set to true once it occurs.
-       isReady: false,
-
-       // A counter to track how many items to wait for before
-       // the ready event fires. See #6781
-       readyWait: 1,
-
-       // Hold (or release) the ready event
-       holdReady: function( hold ) {
-               if ( hold ) {
-                       jQuery.readyWait++;
-               } else {
-                       jQuery.ready( true );
-               }
-       },
-
-       // Handle when the DOM is ready
-       ready: function( wait ) {
-               // Either a released hold or an DOMready/load event and not yet ready
-               if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {
-                       // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
-                       if ( !document.body ) {
-                               return setTimeout( jQuery.ready, 1 );
-                       }
-
-                       // Remember that the DOM is ready
-                       jQuery.isReady = true;
+jQuery.extend( {
 
-                       // If a normal DOM Ready event fired, decrement, and wait if need be
-                       if ( wait !== true && --jQuery.readyWait > 0 ) {
-                               return;
-                       }
+       // Unique for each copy of jQuery on the page
+       expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
 
-                       // If there are functions bound, to execute
-                       readyList.fireWith( document, [ jQuery ] );
+       // Assume jQuery is ready without the ready module
+       isReady: true,
 
-                       // Trigger any bound ready events
-                       if ( jQuery.fn.trigger ) {
-                               jQuery( document ).trigger( "ready" ).off( "ready" );
-                       }
-               }
+       error: function( msg ) {
+               throw new Error( msg );
        },
 
-       bindReady: function() {
-               if ( readyList ) {
-                       return;
-               }
-
-               readyList = jQuery.Callbacks( "once memory" );
-
-               // Catch cases where $(document).ready() is called after the
-               // browser event has already occurred.
-               if ( document.readyState === "complete" ) {
-                       // Handle it asynchronously to allow scripts the opportunity to delay ready
-                       return setTimeout( jQuery.ready, 1 );
-               }
-
-               // Mozilla, Opera and webkit nightlies currently support this event
-               if ( document.addEventListener ) {
-                       // Use the handy event callback
-                       document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
-
-                       // A fallback to window.onload, that will always work
-                       window.addEventListener( "load", jQuery.ready, false );
-
-               // If IE event model is used
-               } else if ( document.attachEvent ) {
-                       // ensure firing before onload,
-                       // maybe late but safe also for iframes
-                       document.attachEvent( "onreadystatechange", DOMContentLoaded );
-
-                       // A fallback to window.onload, that will always work
-                       window.attachEvent( "onload", jQuery.ready );
-
-                       // If IE and not a frame
-                       // continually check to see if the document is ready
-                       var toplevel = false;
-
-                       try {
-                               toplevel = window.frameElement == null;
-                       } catch(e) {}
-
-                       if ( document.documentElement.doScroll && toplevel ) {
-                               doScrollCheck();
-                       }
-               }
-       },
+       noop: function() {},
 
-       // See test/unit/core.js for details concerning isFunction.
-       // Since version 1.3, DOM methods and functions like alert
-       // aren't supported. They return false on IE (#2968).
        isFunction: function( obj ) {
-               return jQuery.type(obj) === "function";
+               return jQuery.type( obj ) === "function";
        },
 
-       isArray: Array.isArray || function( obj ) {
-               return jQuery.type(obj) === "array";
-       },
+       isArray: Array.isArray,
 
        isWindow: function( obj ) {
-               return obj != null && obj == obj.window;
+               return obj != null && obj === obj.window;
        },
 
        isNumeric: function( obj ) {
-               return !isNaN( parseFloat(obj) ) && isFinite( obj );
-       },
 
-       type: function( obj ) {
-               return obj == null ?
-                       String( obj ) :
-                       class2type[ toString.call(obj) ] || "object";
+               // As of jQuery 3.0, isNumeric is limited to
+               // strings and numbers (primitives or objects)
+               // that can be coerced to finite numbers (gh-2662)
+               var type = jQuery.type( obj );
+               return ( type === "number" || type === "string" ) &&
+
+                       // parseFloat NaNs numeric-cast false positives ("")
+                       // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
+                       // subtraction forces infinities to NaN
+                       !isNaN( obj - parseFloat( obj ) );
        },
 
        isPlainObject: function( obj ) {
-               // Must be an Object.
-               // Because of IE, we also have to check the presence of the constructor property.
-               // Make sure that DOM nodes and window objects don't pass through, as well
-               if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
-                       return false;
-               }
+               var proto, Ctor;
 
-               try {
-                       // Not own constructor property must be Object
-                       if ( obj.constructor &&
-                               !hasOwn.call(obj, "constructor") &&
-                               !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
-                               return false;
-                       }
-               } catch ( e ) {
-                       // IE8,9 Will throw exceptions on certain host objects #9897
+               // Detect obvious negatives
+               // Use toString instead of jQuery.type to catch host objects
+               if ( !obj || toString.call( obj ) !== "[object Object]" ) {
                        return false;
                }
 
-               // Own properties are enumerated firstly, so to speed up,
-               // if last one is own, then all properties are own.
+               proto = getProto( obj );
 
-               var key;
-               for ( key in obj ) {}
+               // Objects with no prototype (e.g., `Object.create( null )`) are plain
+               if ( !proto ) {
+                       return true;
+               }
 
-               return key === undefined || hasOwn.call( obj, key );
+               // Objects with prototype are plain iff they were constructed by a global Object function
+               Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
+               return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
        },
 
        isEmptyObject: function( obj ) {
-               for ( var name in obj ) {
+
+               /* eslint-disable no-unused-vars */
+               // See https://github.com/eslint/eslint/issues/6125
+               var name;
+
+               for ( name in obj ) {
                        return false;
                }
                return true;
        },
 
-       error: function( msg ) {
-               throw new Error( msg );
-       },
-
-       parseJSON: function( data ) {
-               if ( typeof data !== "string" || !data ) {
-                       return null;
-               }
-
-               // Make sure leading/trailing whitespace is removed (IE can't handle it)
-               data = jQuery.trim( data );
-
-               // Attempt to parse using the native JSON parser first
-               if ( window.JSON && window.JSON.parse ) {
-                       return window.JSON.parse( data );
-               }
-
-               // Make sure the incoming data is actual JSON
-               // Logic borrowed from http://json.org/json2.js
-               if ( rvalidchars.test( data.replace( rvalidescape, "@" )
-                       .replace( rvalidtokens, "]" )
-                       .replace( rvalidbraces, "")) ) {
-
-                       return ( new Function( "return " + data ) )();
-
+       type: function( obj ) {
+               if ( obj == null ) {
+                       return obj + "";
                }
-               jQuery.error( "Invalid JSON: " + data );
-       },
 
-       // Cross-browser xml parsing
-       parseXML: function( data ) {
-               if ( typeof data !== "string" || !data ) {
-                       return null;
-               }
-               var xml, tmp;
-               try {
-                       if ( window.DOMParser ) { // Standard
-                               tmp = new DOMParser();
-                               xml = tmp.parseFromString( data , "text/xml" );
-                       } else { // IE
-                               xml = new ActiveXObject( "Microsoft.XMLDOM" );
-                               xml.async = "false";
-                               xml.loadXML( data );
-                       }
-               } catch( e ) {
-                       xml = undefined;
-               }
-               if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
-                       jQuery.error( "Invalid XML: " + data );
-               }
-               return xml;
+               // Support: Android <=2.3 only (functionish RegExp)
+               return typeof obj === "object" || typeof obj === "function" ?
+                       class2type[ toString.call( obj ) ] || "object" :
+                       typeof obj;
        },
 
-       noop: function() {},
-
        // Evaluates a script in a global context
-       // Workarounds based on findings by Jim Driscoll
-       // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
-       globalEval: function( data ) {
-               if ( data && rnotwhite.test( data ) ) {
-                       // We use execScript on Internet Explorer
-                       // We use an anonymous function so that context is window
-                       // rather than jQuery in Firefox
-                       ( window.execScript || function( data ) {
-                               window[ "eval" ].call( window, data );
-                       } )( data );
-               }
+       globalEval: function( code ) {
+               DOMEval( code );
        },
 
        // Convert dashed to camelCase; used by the css and data modules
+       // Support: IE <=9 - 11, Edge 12 - 13
        // Microsoft forgot to hump their vendor prefix (#9572)
        camelCase: function( string ) {
                return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
        },
 
        nodeName: function( elem, name ) {
-               return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
+               return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
        },
 
-       // args is for internal usage only
-       each: function( object, callback, args ) {
-               var name, i = 0,
-                       length = object.length,
-                       isObj = length === undefined || jQuery.isFunction( object );
+       each: function( obj, callback ) {
+               var length, i = 0;
 
-               if ( args ) {
-                       if ( isObj ) {
-                               for ( name in object ) {
-                                       if ( callback.apply( object[ name ], args ) === false ) {
-                                               break;
-                                       }
-                               }
-                       } else {
-                               for ( ; i < length; ) {
-                                       if ( callback.apply( object[ i++ ], args ) === false ) {
-                                               break;
-                                       }
+               if ( isArrayLike( obj ) ) {
+                       length = obj.length;
+                       for ( ; i < length; i++ ) {
+                               if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
+                                       break;
                                }
                        }
-
-               // A special, fast, case for the most common use of each
                } else {
-                       if ( isObj ) {
-                               for ( name in object ) {
-                                       if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
-                                               break;
-                                       }
-                               }
-                       } else {
-                               for ( ; i < length; ) {
-                                       if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {
-                                               break;
-                                       }
+                       for ( i in obj ) {
+                               if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
+                                       break;
                                }
                        }
                }
 
-               return object;
+               return obj;
        },
 
-       // Use native String.trim function wherever possible
-       trim: trim ?
-               function( text ) {
-                       return text == null ?
-                               "" :
-                               trim.call( text );
-               } :
-
-               // Otherwise use our own trimming functionality
-               function( text ) {
-                       return text == null ?
-                               "" :
-                               text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
-               },
+       // Support: Android <=4.0 only
+       trim: function( text ) {
+               return text == null ?
+                       "" :
+                       ( text + "" ).replace( rtrim, "" );
+       },
 
        // results is for internal usage only
-       makeArray: function( array, results ) {
+       makeArray: function( arr, results ) {
                var ret = results || [];
 
-               if ( array != null ) {
-                       // The window, strings (and functions) also have 'length'
-                       // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
-                       var type = jQuery.type( array );
-
-                       if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
-                               push.call( ret, array );
+               if ( arr != null ) {
+                       if ( isArrayLike( Object( arr ) ) ) {
+                               jQuery.merge( ret,
+                                       typeof arr === "string" ?
+                                       [ arr ] : arr
+                               );
                        } else {
-                               jQuery.merge( ret, array );
+                               push.call( ret, arr );
                        }
                }
 
                return ret;
        },
 
-       inArray: function( elem, array, i ) {
-               var len;
-
-               if ( array ) {
-                       if ( indexOf ) {
-                               return indexOf.call( array, elem, i );
-                       }
-
-                       len = array.length;
-                       i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
-
-                       for ( ; i < len; i++ ) {
-                               // Skip accessing in sparse arrays
-                               if ( i in array && array[ i ] === elem ) {
-                                       return i;
-                               }
-                       }
-               }
-
-               return -1;
+       inArray: function( elem, arr, i ) {
+               return arr == null ? -1 : indexOf.call( arr, elem, i );
        },
 
+       // Support: Android <=4.0 only, PhantomJS 1 only
+       // push.apply(_, arraylike) throws on ancient WebKit
        merge: function( first, second ) {
-               var i = first.length,
-                       j = 0;
-
-               if ( typeof second.length === "number" ) {
-                       for ( var l = second.length; j < l; j++ ) {
-                               first[ i++ ] = second[ j ];
-                       }
+               var len = +second.length,
+                       j = 0,
+                       i = first.length;
 
-               } else {
-                       while ( second[j] !== undefined ) {
-                               first[ i++ ] = second[ j++ ];
-                       }
+               for ( ; j < len; j++ ) {
+                       first[ i++ ] = second[ j ];
                }
 
                first.length = i;
@@ -743,53 +425,55 @@ jQuery.extend({
                return first;
        },
 
-       grep: function( elems, callback, inv ) {
-               var ret = [], retVal;
-               inv = !!inv;
+       grep: function( elems, callback, invert ) {
+               var callbackInverse,
+                       matches = [],
+                       i = 0,
+                       length = elems.length,
+                       callbackExpect = !invert;
 
                // Go through the array, only saving the items
                // that pass the validator function
-               for ( var i = 0, length = elems.length; i < length; i++ ) {
-                       retVal = !!callback( elems[ i ], i );
-                       if ( inv !== retVal ) {
-                               ret.push( elems[ i ] );
+               for ( ; i < length; i++ ) {
+                       callbackInverse = !callback( elems[ i ], i );
+                       if ( callbackInverse !== callbackExpect ) {
+                               matches.push( elems[ i ] );
                        }
                }
 
-               return ret;
+               return matches;
        },
 
        // arg is for internal usage only
        map: function( elems, callback, arg ) {
-               var value, key, ret = [],
+               var length, value,
                        i = 0,
-                       length = elems.length,
-                       // jquery objects are treated as arrays
-                       isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
+                       ret = [];
 
-               // Go through the array, translating each of the items to their
-               if ( isArray ) {
+               // Go through the array, translating each of the items to their new values
+               if ( isArrayLike( elems ) ) {
+                       length = elems.length;
                        for ( ; i < length; i++ ) {
                                value = callback( elems[ i ], i, arg );
 
                                if ( value != null ) {
-                                       ret[ ret.length ] = value;
+                                       ret.push( value );
                                }
                        }
 
                // Go through every key on the object,
                } else {
-                       for ( key in elems ) {
-                               value = callback( elems[ key ], key, arg );
+                       for ( i in elems ) {
+                               value = callback( elems[ i ], i, arg );
 
                                if ( value != null ) {
-                                       ret[ ret.length ] = value;
+                                       ret.push( value );
                                }
                        }
                }
 
                // Flatten any nested arrays
-               return ret.concat.apply( [], ret );
+               return concat.apply( [], ret );
        },
 
        // A global GUID counter for objects
@@ -798,8 +482,10 @@ jQuery.extend({
        // Bind a function to a context, optionally partially applying any
        // arguments.
        proxy: function( fn, context ) {
+               var tmp, args, proxy;
+
                if ( typeof context === "string" ) {
-                       var tmp = fn[ context ];
+                       tmp = fn[ context ];
                        context = fn;
                        fn = tmp;
                }
@@ -811,6151 +497,6095 @@ jQuery.extend({
                }
 
                // Simulated bind
-               var args = slice.call( arguments, 2 ),
-                       proxy = function() {
-                               return fn.apply( context, args.concat( slice.call( arguments ) ) );
-                       };
+               args = slice.call( arguments, 2 );
+               proxy = function() {
+                       return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
+               };
 
                // Set the guid of unique handler to the same of original handler, so it can be removed
-               proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
+               proxy.guid = fn.guid = fn.guid || jQuery.guid++;
 
                return proxy;
        },
 
-       // Mutifunctional method to get and set values to a collection
-       // The value/s can optionally be executed if it's a function
-       access: function( elems, fn, key, value, chainable, emptyGet, pass ) {
-               var exec,
-                       bulk = key == null,
-                       i = 0,
-                       length = elems.length;
+       now: Date.now,
 
-               // Sets many values
-               if ( key && typeof key === "object" ) {
-                       for ( i in key ) {
-                               jQuery.access( elems, fn, i, key[i], 1, emptyGet, value );
-                       }
-                       chainable = 1;
+       // jQuery.support is not used in Core but other projects attach their
+       // properties to it so it needs to exist.
+       support: support
+} );
 
-               // Sets one value
-               } else if ( value !== undefined ) {
-                       // Optionally, function values get executed if exec is true
-                       exec = pass === undefined && jQuery.isFunction( value );
+if ( typeof Symbol === "function" ) {
+       jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];
+}
 
-                       if ( bulk ) {
-                               // Bulk operations only iterate when executing function values
-                               if ( exec ) {
-                                       exec = fn;
-                                       fn = function( elem, key, value ) {
-                                               return exec.call( jQuery( elem ), value );
-                                       };
+// Populate the class2type map
+jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
+function( i, name ) {
+       class2type[ "[object " + name + "]" ] = name.toLowerCase();
+} );
 
-                               // Otherwise they run against the entire set
-                               } else {
-                                       fn.call( elems, value );
-                                       fn = null;
-                               }
-                       }
+function isArrayLike( obj ) {
 
-                       if ( fn ) {
-                               for (; i < length; i++ ) {
-                                       fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
-                               }
-                       }
+       // Support: real iOS 8.2 only (not reproducible in simulator)
+       // `in` check used to prevent JIT error (gh-2145)
+       // hasOwn isn't used here due to false negatives
+       // regarding Nodelist length in IE
+       var length = !!obj && "length" in obj && obj.length,
+               type = jQuery.type( obj );
 
-                       chainable = 1;
-               }
-
-               return chainable ?
-                       elems :
+       if ( type === "function" || jQuery.isWindow( obj ) ) {
+               return false;
+       }
 
-                       // Gets
-                       bulk ?
-                               fn.call( elems ) :
-                               length ? fn( elems[0], key ) : emptyGet;
+       return type === "array" || length === 0 ||
+               typeof length === "number" && length > 0 && ( length - 1 ) in obj;
+}
+var Sizzle =
+/*!
+ * Sizzle CSS Selector Engine v2.3.3
+ * https://sizzlejs.com/
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2016-08-08
+ */
+(function( window ) {
+
+var i,
+       support,
+       Expr,
+       getText,
+       isXML,
+       tokenize,
+       compile,
+       select,
+       outermostContext,
+       sortInput,
+       hasDuplicate,
+
+       // Local document vars
+       setDocument,
+       document,
+       docElem,
+       documentIsHTML,
+       rbuggyQSA,
+       rbuggyMatches,
+       matches,
+       contains,
+
+       // Instance-specific data
+       expando = "sizzle" + 1 * new Date(),
+       preferredDoc = window.document,
+       dirruns = 0,
+       done = 0,
+       classCache = createCache(),
+       tokenCache = createCache(),
+       compilerCache = createCache(),
+       sortOrder = function( a, b ) {
+               if ( a === b ) {
+                       hasDuplicate = true;
+               }
+               return 0;
        },
 
-       now: function() {
-               return ( new Date() ).getTime();
+       // Instance methods
+       hasOwn = ({}).hasOwnProperty,
+       arr = [],
+       pop = arr.pop,
+       push_native = arr.push,
+       push = arr.push,
+       slice = arr.slice,
+       // Use a stripped-down indexOf as it's faster than native
+       // https://jsperf.com/thor-indexof-vs-for/5
+       indexOf = function( list, elem ) {
+               var i = 0,
+                       len = list.length;
+               for ( ; i < len; i++ ) {
+                       if ( list[i] === elem ) {
+                               return i;
+                       }
+               }
+               return -1;
        },
 
-       // Use of jQuery.browser is frowned upon.
-       // More details: http://docs.jquery.com/Utilities/jQuery.browser
-       uaMatch: function( ua ) {
-               ua = ua.toLowerCase();
+       booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
 
-               var match = rwebkit.exec( ua ) ||
-                       ropera.exec( ua ) ||
-                       rmsie.exec( ua ) ||
-                       ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
-                       [];
+       // Regular expressions
 
-               return { browser: match[1] || "", version: match[2] || "0" };
-       },
+       // http://www.w3.org/TR/css3-selectors/#whitespace
+       whitespace = "[\\x20\\t\\r\\n\\f]",
 
-       sub: function() {
-               function jQuerySub( selector, context ) {
-                       return new jQuerySub.fn.init( selector, context );
-               }
-               jQuery.extend( true, jQuerySub, this );
-               jQuerySub.superclass = this;
-               jQuerySub.fn = jQuerySub.prototype = this();
-               jQuerySub.fn.constructor = jQuerySub;
-               jQuerySub.sub = this.sub;
-               jQuerySub.fn.init = function init( selector, context ) {
-                       if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
-                               context = jQuerySub( context );
-                       }
+       // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+       identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+",
 
-                       return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
-               };
-               jQuerySub.fn.init.prototype = jQuerySub.fn;
-               var rootjQuerySub = jQuerySub(document);
-               return jQuerySub;
-       },
+       // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
+       attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
+               // Operator (capture 2)
+               "*([*^$|!~]?=)" + whitespace +
+               // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
+               "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
+               "*\\]",
 
-       browser: {}
-});
+       pseudos = ":(" + identifier + ")(?:\\((" +
+               // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
+               // 1. quoted (capture 3; capture 4 or capture 5)
+               "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
+               // 2. simple (capture 6)
+               "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
+               // 3. anything else (capture 2)
+               ".*" +
+               ")\\)|)",
 
-// Populate the class2type map
-jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
-       class2type[ "[object " + name + "]" ] = name.toLowerCase();
-});
+       // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+       rwhitespace = new RegExp( whitespace + "+", "g" ),
+       rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
 
-browserMatch = jQuery.uaMatch( userAgent );
-if ( browserMatch.browser ) {
-       jQuery.browser[ browserMatch.browser ] = true;
-       jQuery.browser.version = browserMatch.version;
-}
+       rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+       rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
 
-// Deprecated, use jQuery.browser.webkit instead
-if ( jQuery.browser.webkit ) {
-       jQuery.browser.safari = true;
-}
+       rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
 
-// IE doesn't match non-breaking spaces with \s
-if ( rnotwhite.test( "\xA0" ) ) {
-       trimLeft = /^[\s\xA0]+/;
-       trimRight = /[\s\xA0]+$/;
-}
+       rpseudo = new RegExp( pseudos ),
+       ridentifier = new RegExp( "^" + identifier + "$" ),
 
-// All jQuery objects should point back to these
-rootjQuery = jQuery(document);
+       matchExpr = {
+               "ID": new RegExp( "^#(" + identifier + ")" ),
+               "CLASS": new RegExp( "^\\.(" + identifier + ")" ),
+               "TAG": new RegExp( "^(" + identifier + "|[*])" ),
+               "ATTR": new RegExp( "^" + attributes ),
+               "PSEUDO": new RegExp( "^" + pseudos ),
+               "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
+                       "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
+                       "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+               "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
+               // For use in libraries implementing .is()
+               // We use this for POS matching in `select`
+               "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
+                       whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
+       },
 
-// Cleanup functions for the document ready method
-if ( document.addEventListener ) {
-       DOMContentLoaded = function() {
-               document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
-               jQuery.ready();
-       };
+       rinputs = /^(?:input|select|textarea|button)$/i,
+       rheader = /^h\d$/i,
 
-} else if ( document.attachEvent ) {
-       DOMContentLoaded = function() {
-               // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
-               if ( document.readyState === "complete" ) {
-                       document.detachEvent( "onreadystatechange", DOMContentLoaded );
-                       jQuery.ready();
-               }
-       };
-}
+       rnative = /^[^{]+\{\s*\[native \w/,
 
-// The DOM ready check for Internet Explorer
-function doScrollCheck() {
-       if ( jQuery.isReady ) {
-               return;
-       }
+       // Easily-parseable/retrievable ID or TAG or CLASS selectors
+       rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
 
-       try {
-               // If IE is used, use the trick by Diego Perini
-               // http://javascript.nwbox.com/IEContentLoaded/
-               document.documentElement.doScroll("left");
-       } catch(e) {
-               setTimeout( doScrollCheck, 1 );
-               return;
-       }
+       rsibling = /[+~]/,
 
-       // and execute any waiting functions
-       jQuery.ready();
-}
+       // CSS escapes
+       // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+       runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
+       funescape = function( _, escaped, escapedWhitespace ) {
+               var high = "0x" + escaped - 0x10000;
+               // NaN means non-codepoint
+               // Support: Firefox<24
+               // Workaround erroneous numeric interpretation of +"0x"
+               return high !== high || escapedWhitespace ?
+                       escaped :
+                       high < 0 ?
+                               // BMP codepoint
+                               String.fromCharCode( high + 0x10000 ) :
+                               // Supplemental Plane codepoint (surrogate pair)
+                               String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
+       },
 
-return jQuery;
+       // CSS string/identifier serialization
+       // https://drafts.csswg.org/cssom/#common-serializing-idioms
+       rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,
+       fcssescape = function( ch, asCodePoint ) {
+               if ( asCodePoint ) {
 
-})();
+                       // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
+                       if ( ch === "\0" ) {
+                               return "\uFFFD";
+                       }
 
+                       // Control characters and (dependent upon position) numbers get escaped as code points
+                       return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
+               }
 
-// String to Object flags format cache
-var flagsCache = {};
+               // Other potentially-special ASCII characters get backslash-escaped
+               return "\\" + ch;
+       },
+
+       // Used for iframes
+       // See setDocument()
+       // Removing the function wrapper causes a "Permission Denied"
+       // error in IE
+       unloadHandler = function() {
+               setDocument();
+       },
+
+       disabledAncestor = addCombinator(
+               function( elem ) {
+                       return elem.disabled === true && ("form" in elem || "label" in elem);
+               },
+               { dir: "parentNode", next: "legend" }
+       );
 
-// Convert String-formatted flags into Object-formatted ones and store in cache
-function createFlags( flags ) {
-       var object = flagsCache[ flags ] = {},
-               i, length;
-       flags = flags.split( /\s+/ );
-       for ( i = 0, length = flags.length; i < length; i++ ) {
-               object[ flags[i] ] = true;
-       }
-       return object;
-}
+// Optimize for push.apply( _, NodeList )
+try {
+       push.apply(
+               (arr = slice.call( preferredDoc.childNodes )),
+               preferredDoc.childNodes
+       );
+       // Support: Android<4.0
+       // Detect silently failing push.apply
+       arr[ preferredDoc.childNodes.length ].nodeType;
+} catch ( e ) {
+       push = { apply: arr.length ?
+
+               // Leverage slice if possible
+               function( target, els ) {
+                       push_native.apply( target, slice.call(els) );
+               } :
 
-/*
- * Create a callback list using the following parameters:
- *
- *     flags:  an optional list of space-separated flags that will change how
- *                     the callback list behaves
- *
- * By default a callback list will act like an event callback list and can be
- * "fired" multiple times.
- *
- * Possible flags:
- *
- *     once:                   will ensure the callback list can only be fired once (like a Deferred)
- *
- *     memory:                 will keep track of previous values and will call any callback added
- *                                     after the list has been fired right away with the latest "memorized"
- *                                     values (like a Deferred)
- *
- *     unique:                 will ensure a callback can only be added once (no duplicate in the list)
- *
- *     stopOnFalse:    interrupt callings when a callback returns false
- *
- */
-jQuery.Callbacks = function( flags ) {
+               // Support: IE<9
+               // Otherwise append directly
+               function( target, els ) {
+                       var j = target.length,
+                               i = 0;
+                       // Can't trust NodeList.length
+                       while ( (target[j++] = els[i++]) ) {}
+                       target.length = j - 1;
+               }
+       };
+}
 
-       // Convert flags from String-formatted to Object-formatted
-       // (we check in cache first)
-       flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};
+function Sizzle( selector, context, results, seed ) {
+       var m, i, elem, nid, match, groups, newSelector,
+               newContext = context && context.ownerDocument,
 
-       var // Actual callback list
-               list = [],
-               // Stack of fire calls for repeatable lists
-               stack = [],
-               // Last fire value (for non-forgettable lists)
-               memory,
-               // Flag to know if list was already fired
-               fired,
-               // Flag to know if list is currently firing
-               firing,
-               // First callback to fire (used internally by add and fireWith)
-               firingStart,
-               // End of the loop when firing
-               firingLength,
-               // Index of currently firing callback (modified by remove if needed)
-               firingIndex,
-               // Add one or several callbacks to the list
-               add = function( args ) {
-                       var i,
-                               length,
-                               elem,
-                               type,
-                               actual;
-                       for ( i = 0, length = args.length; i < length; i++ ) {
-                               elem = args[ i ];
-                               type = jQuery.type( elem );
-                               if ( type === "array" ) {
-                                       // Inspect recursively
-                                       add( elem );
-                               } else if ( type === "function" ) {
-                                       // Add if not in unique mode and callback is not in
-                                       if ( !flags.unique || !self.has( elem ) ) {
-                                               list.push( elem );
-                                       }
-                               }
-                       }
-               },
-               // Fire callbacks
-               fire = function( context, args ) {
-                       args = args || [];
-                       memory = !flags.memory || [ context, args ];
-                       fired = true;
-                       firing = true;
-                       firingIndex = firingStart || 0;
-                       firingStart = 0;
-                       firingLength = list.length;
-                       for ( ; list && firingIndex < firingLength; firingIndex++ ) {
-                               if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {
-                                       memory = true; // Mark as halted
-                                       break;
-                               }
-                       }
-                       firing = false;
-                       if ( list ) {
-                               if ( !flags.once ) {
-                                       if ( stack && stack.length ) {
-                                               memory = stack.shift();
-                                               self.fireWith( memory[ 0 ], memory[ 1 ] );
-                                       }
-                               } else if ( memory === true ) {
-                                       self.disable();
-                               } else {
-                                       list = [];
-                               }
-                       }
-               },
-               // Actual Callbacks object
-               self = {
-                       // Add a callback or a collection of callbacks to the list
-                       add: function() {
-                               if ( list ) {
-                                       var length = list.length;
-                                       add( arguments );
-                                       // Do we need to add the callbacks to the
-                                       // current firing batch?
-                                       if ( firing ) {
-                                               firingLength = list.length;
-                                       // With memory, if we're not firing then
-                                       // we should call right away, unless previous
-                                       // firing was halted (stopOnFalse)
-                                       } else if ( memory && memory !== true ) {
-                                               firingStart = length;
-                                               fire( memory[ 0 ], memory[ 1 ] );
-                                       }
-                               }
-                               return this;
-                       },
-                       // Remove a callback from the list
-                       remove: function() {
-                               if ( list ) {
-                                       var args = arguments,
-                                               argIndex = 0,
-                                               argLength = args.length;
-                                       for ( ; argIndex < argLength ; argIndex++ ) {
-                                               for ( var i = 0; i < list.length; i++ ) {
-                                                       if ( args[ argIndex ] === list[ i ] ) {
-                                                               // Handle firingIndex and firingLength
-                                                               if ( firing ) {
-                                                                       if ( i <= firingLength ) {
-                                                                               firingLength--;
-                                                                               if ( i <= firingIndex ) {
-                                                                                       firingIndex--;
-                                                                               }
-                                                                       }
-                                                               }
-                                                               // Remove the element
-                                                               list.splice( i--, 1 );
-                                                               // If we have some unicity property then
-                                                               // we only need to do this once
-                                                               if ( flags.unique ) {
-                                                                       break;
-                                                               }
-                                                       }
-                                               }
-                                       }
-                               }
-                               return this;
-                       },
-                       // Control if a given callback is in the list
-                       has: function( fn ) {
-                               if ( list ) {
-                                       var i = 0,
-                                               length = list.length;
-                                       for ( ; i < length; i++ ) {
-                                               if ( fn === list[ i ] ) {
-                                                       return true;
-                                               }
-                                       }
-                               }
-                               return false;
-                       },
-                       // Remove all callbacks from the list
-                       empty: function() {
-                               list = [];
-                               return this;
-                       },
-                       // Have the list do nothing anymore
-                       disable: function() {
-                               list = stack = memory = undefined;
-                               return this;
-                       },
-                       // Is it disabled?
-                       disabled: function() {
-                               return !list;
-                       },
-                       // Lock the list in its current state
-                       lock: function() {
-                               stack = undefined;
-                               if ( !memory || memory === true ) {
-                                       self.disable();
-                               }
-                               return this;
-                       },
-                       // Is it locked?
-                       locked: function() {
-                               return !stack;
-                       },
-                       // Call all callbacks with the given context and arguments
-                       fireWith: function( context, args ) {
-                               if ( stack ) {
-                                       if ( firing ) {
-                                               if ( !flags.once ) {
-                                                       stack.push( [ context, args ] );
-                                               }
-                                       } else if ( !( flags.once && memory ) ) {
-                                               fire( context, args );
-                                       }
-                               }
-                               return this;
-                       },
-                       // Call all the callbacks with the given arguments
-                       fire: function() {
-                               self.fireWith( this, arguments );
-                               return this;
-                       },
-                       // To know if the callbacks have already been called at least once
-                       fired: function() {
-                               return !!fired;
-                       }
-               };
+               // nodeType defaults to 9, since context defaults to document
+               nodeType = context ? context.nodeType : 9;
 
-       return self;
-};
+       results = results || [];
 
+       // Return early from calls with invalid selector or context
+       if ( typeof selector !== "string" || !selector ||
+               nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
 
+               return results;
+       }
 
+       // Try to shortcut find operations (as opposed to filters) in HTML documents
+       if ( !seed ) {
 
-var // Static reference to slice
-       sliceDeferred = [].slice;
+               if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
+                       setDocument( context );
+               }
+               context = context || document;
 
-jQuery.extend({
+               if ( documentIsHTML ) {
 
-       Deferred: function( func ) {
-               var doneList = jQuery.Callbacks( "once memory" ),
-                       failList = jQuery.Callbacks( "once memory" ),
-                       progressList = jQuery.Callbacks( "memory" ),
-                       state = "pending",
-                       lists = {
-                               resolve: doneList,
-                               reject: failList,
-                               notify: progressList
-                       },
-                       promise = {
-                               done: doneList.add,
-                               fail: failList.add,
-                               progress: progressList.add,
+                       // If the selector is sufficiently simple, try using a "get*By*" DOM method
+                       // (excepting DocumentFragment context, where the methods don't exist)
+                       if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
 
-                               state: function() {
-                                       return state;
-                               },
+                               // ID selector
+                               if ( (m = match[1]) ) {
 
-                               // Deprecated
-                               isResolved: doneList.fired,
-                               isRejected: failList.fired,
+                                       // Document context
+                                       if ( nodeType === 9 ) {
+                                               if ( (elem = context.getElementById( m )) ) {
 
-                               then: function( doneCallbacks, failCallbacks, progressCallbacks ) {
-                                       deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks );
-                                       return this;
-                               },
-                               always: function() {
-                                       deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments );
-                                       return this;
-                               },
-                               pipe: function( fnDone, fnFail, fnProgress ) {
-                                       return jQuery.Deferred(function( newDefer ) {
-                                               jQuery.each( {
-                                                       done: [ fnDone, "resolve" ],
-                                                       fail: [ fnFail, "reject" ],
-                                                       progress: [ fnProgress, "notify" ]
-                                               }, function( handler, data ) {
-                                                       var fn = data[ 0 ],
-                                                               action = data[ 1 ],
-                                                               returned;
-                                                       if ( jQuery.isFunction( fn ) ) {
-                                                               deferred[ handler ](function() {
-                                                                       returned = fn.apply( this, arguments );
-                                                                       if ( returned && jQuery.isFunction( returned.promise ) ) {
-                                                                               returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify );
-                                                                       } else {
-                                                                               newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
-                                                                       }
-                                                               });
-                                                       } else {
-                                                               deferred[ handler ]( newDefer[ action ] );
+                                                       // Support: IE, Opera, Webkit
+                                                       // TODO: identify versions
+                                                       // getElementById can match elements by name instead of ID
+                                                       if ( elem.id === m ) {
+                                                               results.push( elem );
+                                                               return results;
                                                        }
-                                               });
-                                       }).promise();
-                               },
-                               // Get a promise for this deferred
-                               // If obj is provided, the promise aspect is added to the object
-                               promise: function( obj ) {
-                                       if ( obj == null ) {
-                                               obj = promise;
+                                               } else {
+                                                       return results;
+                                               }
+
+                                       // Element context
                                        } else {
-                                               for ( var key in promise ) {
-                                                       obj[ key ] = promise[ key ];
+
+                                               // Support: IE, Opera, Webkit
+                                               // TODO: identify versions
+                                               // getElementById can match elements by name instead of ID
+                                               if ( newContext && (elem = newContext.getElementById( m )) &&
+                                                       contains( context, elem ) &&
+                                                       elem.id === m ) {
+
+                                                       results.push( elem );
+                                                       return results;
                                                }
                                        }
-                                       return obj;
+
+                               // Type selector
+                               } else if ( match[2] ) {
+                                       push.apply( results, context.getElementsByTagName( selector ) );
+                                       return results;
+
+                               // Class selector
+                               } else if ( (m = match[3]) && support.getElementsByClassName &&
+                                       context.getElementsByClassName ) {
+
+                                       push.apply( results, context.getElementsByClassName( m ) );
+                                       return results;
                                }
-                       },
-                       deferred = promise.promise({}),
-                       key;
+                       }
 
-               for ( key in lists ) {
-                       deferred[ key ] = lists[ key ].fire;
-                       deferred[ key + "With" ] = lists[ key ].fireWith;
-               }
+                       // Take advantage of querySelectorAll
+                       if ( support.qsa &&
+                               !compilerCache[ selector + " " ] &&
+                               (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
 
-               // Handle state
-               deferred.done( function() {
-                       state = "resolved";
-               }, failList.disable, progressList.lock ).fail( function() {
-                       state = "rejected";
-               }, doneList.disable, progressList.lock );
+                               if ( nodeType !== 1 ) {
+                                       newContext = context;
+                                       newSelector = selector;
 
-               // Call given func if any
-               if ( func ) {
-                       func.call( deferred, deferred );
-               }
+                               // qSA looks outside Element context, which is not what we want
+                               // Thanks to Andrew Dupont for this workaround technique
+                               // Support: IE <=8
+                               // Exclude object elements
+                               } else if ( context.nodeName.toLowerCase() !== "object" ) {
 
-               // All done!
-               return deferred;
-       },
+                                       // Capture the context ID, setting it first if necessary
+                                       if ( (nid = context.getAttribute( "id" )) ) {
+                                               nid = nid.replace( rcssescape, fcssescape );
+                                       } else {
+                                               context.setAttribute( "id", (nid = expando) );
+                                       }
 
-       // Deferred helper
-       when: function( firstParam ) {
-               var args = sliceDeferred.call( arguments, 0 ),
-                       i = 0,
-                       length = args.length,
-                       pValues = new Array( length ),
-                       count = length,
-                       pCount = length,
-                       deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
-                               firstParam :
-                               jQuery.Deferred(),
-                       promise = deferred.promise();
-               function resolveFunc( i ) {
-                       return function( value ) {
-                               args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
-                               if ( !( --count ) ) {
-                                       deferred.resolveWith( deferred, args );
+                                       // Prefix every selector in the list
+                                       groups = tokenize( selector );
+                                       i = groups.length;
+                                       while ( i-- ) {
+                                               groups[i] = "#" + nid + " " + toSelector( groups[i] );
+                                       }
+                                       newSelector = groups.join( "," );
+
+                                       // Expand context for sibling selectors
+                                       newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
+                                               context;
                                }
-                       };
-               }
-               function progressFunc( i ) {
-                       return function( value ) {
-                               pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
-                               deferred.notifyWith( promise, pValues );
-                       };
-               }
-               if ( length > 1 ) {
-                       for ( ; i < length; i++ ) {
-                               if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) {
-                                       args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) );
-                               } else {
-                                       --count;
+
+                               if ( newSelector ) {
+                                       try {
+                                               push.apply( results,
+                                                       newContext.querySelectorAll( newSelector )
+                                               );
+                                               return results;
+                                       } catch ( qsaError ) {
+                                       } finally {
+                                               if ( nid === expando ) {
+                                                       context.removeAttribute( "id" );
+                                               }
+                                       }
                                }
                        }
-                       if ( !count ) {
-                               deferred.resolveWith( deferred, args );
-                       }
-               } else if ( deferred !== firstParam ) {
-                       deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
                }
-               return promise;
        }
-});
 
+       // All others
+       return select( selector.replace( rtrim, "$1" ), context, results, seed );
+}
 
+/**
+ * Create key-value caches of limited size
+ * @returns {function(string, object)} Returns the Object data after storing it on itself with
+ *     property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
+ *     deleting the oldest entry
+ */
+function createCache() {
+       var keys = [];
 
+       function cache( key, value ) {
+               // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
+               if ( keys.push( key + " " ) > Expr.cacheLength ) {
+                       // Only keep the most recent entries
+                       delete cache[ keys.shift() ];
+               }
+               return (cache[ key + " " ] = value);
+       }
+       return cache;
+}
 
-jQuery.support = (function() {
-
-       var support,
-               all,
-               a,
-               select,
-               opt,
-               input,
-               fragment,
-               tds,
-               events,
-               eventName,
-               i,
-               isSupported,
-               div = document.createElement( "div" ),
-               documentElement = document.documentElement;
-
-       // Preliminary tests
-       div.setAttribute("className", "t");
-       div.innerHTML = "   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
-
-       all = div.getElementsByTagName( "*" );
-       a = div.getElementsByTagName( "a" )[ 0 ];
-
-       // Can't get basic test support
-       if ( !all || !all.length || !a ) {
-               return {};
-       }
-
-       // First batch of supports tests
-       select = document.createElement( "select" );
-       opt = select.appendChild( document.createElement("option") );
-       input = div.getElementsByTagName( "input" )[ 0 ];
-
-       support = {
-               // IE strips leading whitespace when .innerHTML is used
-               leadingWhitespace: ( div.firstChild.nodeType === 3 ),
-
-               // Make sure that tbody elements aren't automatically inserted
-               // IE will insert them into empty tables
-               tbody: !div.getElementsByTagName("tbody").length,
-
-               // Make sure that link elements get serialized correctly by innerHTML
-               // This requires a wrapper element in IE
-               htmlSerialize: !!div.getElementsByTagName("link").length,
-
-               // Get the style information from getAttribute
-               // (IE uses .cssText instead)
-               style: /top/.test( a.getAttribute("style") ),
-
-               // Make sure that URLs aren't manipulated
-               // (IE normalizes it by default)
-               hrefNormalized: ( a.getAttribute("href") === "/a" ),
-
-               // Make sure that element opacity exists
-               // (IE uses filter instead)
-               // Use a regex to work around a WebKit issue. See #5145
-               opacity: /^0.55/.test( a.style.opacity ),
-
-               // Verify style float existence
-               // (IE uses styleFloat instead of cssFloat)
-               cssFloat: !!a.style.cssFloat,
-
-               // Make sure that if no value is specified for a checkbox
-               // that it defaults to "on".
-               // (WebKit defaults to "" instead)
-               checkOn: ( input.value === "on" ),
-
-               // Make sure that a selected-by-default option has a working selected property.
-               // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
-               optSelected: opt.selected,
-
-               // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
-               getSetAttribute: div.className !== "t",
-
-               // Tests for enctype support on a form(#6743)
-               enctype: !!document.createElement("form").enctype,
-
-               // Makes sure cloning an html5 element does not cause problems
-               // Where outerHTML is undefined, this still works
-               html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
-
-               // Will be defined later
-               submitBubbles: true,
-               changeBubbles: true,
-               focusinBubbles: false,
-               deleteExpando: true,
-               noCloneEvent: true,
-               inlineBlockNeedsLayout: false,
-               shrinkWrapBlocks: false,
-               reliableMarginRight: true,
-               pixelMargin: true
-       };
+/**
+ * Mark a function for special use by Sizzle
+ * @param {Function} fn The function to mark
+ */
+function markFunction( fn ) {
+       fn[ expando ] = true;
+       return fn;
+}
 
-       // jQuery.boxModel DEPRECATED in 1.3, use jQuery.support.boxModel instead
-       jQuery.boxModel = support.boxModel = (document.compatMode === "CSS1Compat");
+/**
+ * Support testing using an element
+ * @param {Function} fn Passed the created element and returns a boolean result
+ */
+function assert( fn ) {
+       var el = document.createElement("fieldset");
 
-       // Make sure checked status is properly cloned
-       input.checked = true;
-       support.noCloneChecked = input.cloneNode( true ).checked;
+       try {
+               return !!fn( el );
+       } catch (e) {
+               return false;
+       } finally {
+               // Remove from its parent by default
+               if ( el.parentNode ) {
+                       el.parentNode.removeChild( el );
+               }
+               // release memory in IE
+               el = null;
+       }
+}
 
-       // Make sure that the options inside disabled selects aren't marked as disabled
-       // (WebKit marks them as disabled)
-       select.disabled = true;
-       support.optDisabled = !opt.disabled;
+/**
+ * Adds the same handler for all of the specified attrs
+ * @param {String} attrs Pipe-separated list of attributes
+ * @param {Function} handler The method that will be applied
+ */
+function addHandle( attrs, handler ) {
+       var arr = attrs.split("|"),
+               i = arr.length;
 
-       // Test to see if it's possible to delete an expando from an element
-       // Fails in Internet Explorer
-       try {
-               delete div.test;
-       } catch( e ) {
-               support.deleteExpando = false;
+       while ( i-- ) {
+               Expr.attrHandle[ arr[i] ] = handler;
        }
+}
 
-       if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
-               div.attachEvent( "onclick", function() {
-                       // Cloning a node shouldn't copy over any
-                       // bound event handlers (IE does this)
-                       support.noCloneEvent = false;
-               });
-               div.cloneNode( true ).fireEvent( "onclick" );
+/**
+ * Checks document order of two siblings
+ * @param {Element} a
+ * @param {Element} b
+ * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
+ */
+function siblingCheck( a, b ) {
+       var cur = b && a,
+               diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
+                       a.sourceIndex - b.sourceIndex;
+
+       // Use IE sourceIndex if available on both nodes
+       if ( diff ) {
+               return diff;
        }
 
-       // Check if a radio maintains its value
-       // after being appended to the DOM
-       input = document.createElement("input");
-       input.value = "t";
-       input.setAttribute("type", "radio");
-       support.radioValue = input.value === "t";
+       // Check if b follows a
+       if ( cur ) {
+               while ( (cur = cur.nextSibling) ) {
+                       if ( cur === b ) {
+                               return -1;
+                       }
+               }
+       }
 
-       input.setAttribute("checked", "checked");
-
-       // #11217 - WebKit loses check when the name is after the checked attribute
-       input.setAttribute( "name", "t" );
+       return a ? 1 : -1;
+}
 
-       div.appendChild( input );
-       fragment = document.createDocumentFragment();
-       fragment.appendChild( div.lastChild );
-
-       // WebKit doesn't clone checked state correctly in fragments
-       support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
-
-       // Check if a disconnected checkbox will retain its checked
-       // value of true after appended to the DOM (IE6/7)
-       support.appendChecked = input.checked;
-
-       fragment.removeChild( input );
-       fragment.appendChild( div );
-
-       // Technique from Juriy Zaytsev
-       // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
-       // We only care about the case where non-standard event systems
-       // are used, namely in IE. Short-circuiting here helps us to
-       // avoid an eval call (in setAttribute) which can cause CSP
-       // to go haywire. See: https://developer.mozilla.org/en/Security/CSP
-       if ( div.attachEvent ) {
-               for ( i in {
-                       submit: 1,
-                       change: 1,
-                       focusin: 1
-               }) {
-                       eventName = "on" + i;
-                       isSupported = ( eventName in div );
-                       if ( !isSupported ) {
-                               div.setAttribute( eventName, "return;" );
-                               isSupported = ( typeof div[ eventName ] === "function" );
-                       }
-                       support[ i + "Bubbles" ] = isSupported;
-               }
-       }
-
-       fragment.removeChild( div );
-
-       // Null elements to avoid leaks in IE
-       fragment = select = opt = div = input = null;
-
-       // Run tests that need a body at doc ready
-       jQuery(function() {
-               var container, outer, inner, table, td, offsetSupport,
-                       marginDiv, conMarginTop, style, html, positionTopLeftWidthHeight,
-                       paddingMarginBorderVisibility, paddingMarginBorder,
-                       body = document.getElementsByTagName("body")[0];
-
-               if ( !body ) {
-                       // Return for frameset docs that don't have a body
-                       return;
-               }
+/**
+ * Returns a function to use in pseudos for input types
+ * @param {String} type
+ */
+function createInputPseudo( type ) {
+       return function( elem ) {
+               var name = elem.nodeName.toLowerCase();
+               return name === "input" && elem.type === type;
+       };
+}
 
-               conMarginTop = 1;
-               paddingMarginBorder = "padding:0;margin:0;border:";
-               positionTopLeftWidthHeight = "position:absolute;top:0;left:0;width:1px;height:1px;";
-               paddingMarginBorderVisibility = paddingMarginBorder + "0;visibility:hidden;";
-               style = "style='" + positionTopLeftWidthHeight + paddingMarginBorder + "5px solid #000;";
-               html = "<div " + style + "display:block;'><div style='" + paddingMarginBorder + "0;display:block;overflow:hidden;'></div></div>" +
-                       "<table " + style + "' cellpadding='0' cellspacing='0'>" +
-                       "<tr><td></td></tr></table>";
-
-               container = document.createElement("div");
-               container.style.cssText = paddingMarginBorderVisibility + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px";
-               body.insertBefore( container, body.firstChild );
-
-               // Construct the test element
-               div = document.createElement("div");
-               container.appendChild( div );
-
-               // Check if table cells still have offsetWidth/Height when they are set
-               // to display:none and there are still other visible table cells in a
-               // table row; if so, offsetWidth/Height are not reliable for use when
-               // determining if an element has been hidden directly using
-               // display:none (it is still safe to use offsets if a parent element is
-               // hidden; don safety goggles and see bug #4512 for more information).
-               // (only IE 8 fails this test)
-               div.innerHTML = "<table><tr><td style='" + paddingMarginBorder + "0;display:none'></td><td>t</td></tr></table>";
-               tds = div.getElementsByTagName( "td" );
-               isSupported = ( tds[ 0 ].offsetHeight === 0 );
-
-               tds[ 0 ].style.display = "";
-               tds[ 1 ].style.display = "none";
-
-               // Check if empty table cells still have offsetWidth/Height
-               // (IE <= 8 fail this test)
-               support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
-
-               // Check if div with explicit width and no margin-right incorrectly
-               // gets computed margin-right based on width of container. For more
-               // info see bug #3333
-               // Fails in WebKit before Feb 2011 nightlies
-               // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
-               if ( window.getComputedStyle ) {
-                       div.innerHTML = "";
-                       marginDiv = document.createElement( "div" );
-                       marginDiv.style.width = "0";
-                       marginDiv.style.marginRight = "0";
-                       div.style.width = "2px";
-                       div.appendChild( marginDiv );
-                       support.reliableMarginRight =
-                               ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;
-               }
-
-               if ( typeof div.style.zoom !== "undefined" ) {
-                       // Check if natively block-level elements act like inline-block
-                       // elements when setting their display to 'inline' and giving
-                       // them layout
-                       // (IE < 8 does this)
-                       div.innerHTML = "";
-                       div.style.width = div.style.padding = "1px";
-                       div.style.border = 0;
-                       div.style.overflow = "hidden";
-                       div.style.display = "inline";
-                       div.style.zoom = 1;
-                       support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
-
-                       // Check if elements with layout shrink-wrap their children
-                       // (IE 6 does this)
-                       div.style.display = "block";
-                       div.style.overflow = "visible";
-                       div.innerHTML = "<div style='width:5px;'></div>";
-                       support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
-               }
-
-               div.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility;
-               div.innerHTML = html;
-
-               outer = div.firstChild;
-               inner = outer.firstChild;
-               td = outer.nextSibling.firstChild.firstChild;
-
-               offsetSupport = {
-                       doesNotAddBorder: ( inner.offsetTop !== 5 ),
-                       doesAddBorderForTableAndCells: ( td.offsetTop === 5 )
-               };
+/**
+ * Returns a function to use in pseudos for buttons
+ * @param {String} type
+ */
+function createButtonPseudo( type ) {
+       return function( elem ) {
+               var name = elem.nodeName.toLowerCase();
+               return (name === "input" || name === "button") && elem.type === type;
+       };
+}
 
-               inner.style.position = "fixed";
-               inner.style.top = "20px";
+/**
+ * Returns a function to use in pseudos for :enabled/:disabled
+ * @param {Boolean} disabled true for :disabled; false for :enabled
+ */
+function createDisabledPseudo( disabled ) {
+
+       // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable
+       return function( elem ) {
+
+               // Only certain elements can match :enabled or :disabled
+               // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled
+               // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled
+               if ( "form" in elem ) {
+
+                       // Check for inherited disabledness on relevant non-disabled elements:
+                       // * listed form-associated elements in a disabled fieldset
+                       //   https://html.spec.whatwg.org/multipage/forms.html#category-listed
+                       //   https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled
+                       // * option elements in a disabled optgroup
+                       //   https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled
+                       // All such elements have a "form" property.
+                       if ( elem.parentNode && elem.disabled === false ) {
+
+                               // Option elements defer to a parent optgroup if present
+                               if ( "label" in elem ) {
+                                       if ( "label" in elem.parentNode ) {
+                                               return elem.parentNode.disabled === disabled;
+                                       } else {
+                                               return elem.disabled === disabled;
+                                       }
+                               }
 
-               // safari subtracts parent border width here which is 5px
-               offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 );
-               inner.style.position = inner.style.top = "";
+                               // Support: IE 6 - 11
+                               // Use the isDisabled shortcut property to check for disabled fieldset ancestors
+                               return elem.isDisabled === disabled ||
 
-               outer.style.overflow = "hidden";
-               outer.style.position = "relative";
+                                       // Where there is no isDisabled, check manually
+                                       /* jshint -W018 */
+                                       elem.isDisabled !== !disabled &&
+                                               disabledAncestor( elem ) === disabled;
+                       }
 
-               offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 );
-               offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop );
+                       return elem.disabled === disabled;
 
-               if ( window.getComputedStyle ) {
-                       div.style.marginTop = "1%";
-                       support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%";
+               // Try to winnow out elements that can't be disabled before trusting the disabled property.
+               // Some victims get caught in our net (label, legend, menu, track), but it shouldn't
+               // even exist on them, let alone have a boolean value.
+               } else if ( "label" in elem ) {
+                       return elem.disabled === disabled;
                }
 
-               if ( typeof container.style.zoom !== "undefined" ) {
-                       container.style.zoom = 1;
-               }
+               // Remaining elements are neither :enabled nor :disabled
+               return false;
+       };
+}
 
-               body.removeChild( container );
-               marginDiv = div = container = null;
+/**
+ * Returns a function to use in pseudos for positionals
+ * @param {Function} fn
+ */
+function createPositionalPseudo( fn ) {
+       return markFunction(function( argument ) {
+               argument = +argument;
+               return markFunction(function( seed, matches ) {
+                       var j,
+                               matchIndexes = fn( [], seed.length, argument ),
+                               i = matchIndexes.length;
 
-               jQuery.extend( support, offsetSupport );
+                       // Match elements found at the specified indexes
+                       while ( i-- ) {
+                               if ( seed[ (j = matchIndexes[i]) ] ) {
+                                       seed[j] = !(matches[j] = seed[j]);
+                               }
+                       }
+               });
        });
+}
 
-       return support;
-})();
-
-
+/**
+ * Checks a node for validity as a Sizzle context
+ * @param {Element|Object=} context
+ * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
+ */
+function testContext( context ) {
+       return context && typeof context.getElementsByTagName !== "undefined" && context;
+}
 
+// Expose support vars for convenience
+support = Sizzle.support = {};
 
-var rbrace = /^(?:\{.*\}|\[.*\])$/,
-       rmultiDash = /([A-Z])/g;
+/**
+ * Detects XML nodes
+ * @param {Element|Object} elem An element or a document
+ * @returns {Boolean} True iff elem is a non-HTML XML node
+ */
+isXML = Sizzle.isXML = function( elem ) {
+       // documentElement is verified for cases where it doesn't yet exist
+       // (such as loading iframes in IE - #4833)
+       var documentElement = elem && (elem.ownerDocument || elem).documentElement;
+       return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
 
-jQuery.extend({
-       cache: {},
+/**
+ * Sets document-related variables once based on the current document
+ * @param {Element|Object} [doc] An element or document object to use to set the document
+ * @returns {Object} Returns the current document
+ */
+setDocument = Sizzle.setDocument = function( node ) {
+       var hasCompare, subWindow,
+               doc = node ? node.ownerDocument || node : preferredDoc;
 
-       // Please use with caution
-       uuid: 0,
+       // Return early if doc is invalid or already selected
+       if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
+               return document;
+       }
 
-       // Unique for each copy of jQuery on the page
-       // Non-digits removed to match rinlinejQuery
-       expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
+       // Update global variables
+       document = doc;
+       docElem = document.documentElement;
+       documentIsHTML = !isXML( document );
 
-       // The following elements throw uncatchable exceptions if you
-       // attempt to add expando properties to them.
-       noData: {
-               "embed": true,
-               // Ban all objects except for Flash (which handle expandos)
-               "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
-               "applet": true
-       },
+       // Support: IE 9-11, Edge
+       // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
+       if ( preferredDoc !== document &&
+               (subWindow = document.defaultView) && subWindow.top !== subWindow ) {
 
-       hasData: function( elem ) {
-               elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
-               return !!elem && !isEmptyDataObject( elem );
-       },
+               // Support: IE 11, Edge
+               if ( subWindow.addEventListener ) {
+                       subWindow.addEventListener( "unload", unloadHandler, false );
 
-       data: function( elem, name, data, pvt /* Internal Use Only */ ) {
-               if ( !jQuery.acceptData( elem ) ) {
-                       return;
+               // Support: IE 9 - 10 only
+               } else if ( subWindow.attachEvent ) {
+                       subWindow.attachEvent( "onunload", unloadHandler );
                }
+       }
 
-               var privateCache, thisCache, ret,
-                       internalKey = jQuery.expando,
-                       getByName = typeof name === "string",
+       /* Attributes
+       ---------------------------------------------------------------------- */
 
-                       // We have to handle DOM nodes and JS objects differently because IE6-7
-                       // can't GC object references properly across the DOM-JS boundary
-                       isNode = elem.nodeType,
+       // Support: IE<8
+       // Verify that getAttribute really returns attributes and not properties
+       // (excepting IE8 booleans)
+       support.attributes = assert(function( el ) {
+               el.className = "i";
+               return !el.getAttribute("className");
+       });
 
-                       // Only DOM nodes need the global jQuery cache; JS object data is
-                       // attached directly to the object so GC can occur automatically
-                       cache = isNode ? jQuery.cache : elem,
+       /* getElement(s)By*
+       ---------------------------------------------------------------------- */
 
-                       // Only defining an ID for JS objects if its cache already exists allows
-                       // the code to shortcut on the same path as a DOM node with no cache
-                       id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey,
-                       isEvents = name === "events";
+       // Check if getElementsByTagName("*") returns only elements
+       support.getElementsByTagName = assert(function( el ) {
+               el.appendChild( document.createComment("") );
+               return !el.getElementsByTagName("*").length;
+       });
 
-               // Avoid doing any more work than we need to when trying to get data on an
-               // object that has no data at all
-               if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) {
-                       return;
-               }
+       // Support: IE<9
+       support.getElementsByClassName = rnative.test( document.getElementsByClassName );
 
-               if ( !id ) {
-                       // Only DOM nodes need a new unique ID for each element since their data
-                       // ends up in the global cache
-                       if ( isNode ) {
-                               elem[ internalKey ] = id = ++jQuery.uuid;
-                       } else {
-                               id = internalKey;
+       // Support: IE<10
+       // Check if getElementById returns elements by name
+       // The broken getElementById methods don't pick up programmatically-set names,
+       // so use a roundabout getElementsByName test
+       support.getById = assert(function( el ) {
+               docElem.appendChild( el ).id = expando;
+               return !document.getElementsByName || !document.getElementsByName( expando ).length;
+       });
+
+       // ID filter and find
+       if ( support.getById ) {
+               Expr.filter["ID"] = function( id ) {
+                       var attrId = id.replace( runescape, funescape );
+                       return function( elem ) {
+                               return elem.getAttribute("id") === attrId;
+                       };
+               };
+               Expr.find["ID"] = function( id, context ) {
+                       if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
+                               var elem = context.getElementById( id );
+                               return elem ? [ elem ] : [];
                        }
-               }
+               };
+       } else {
+               Expr.filter["ID"] =  function( id ) {
+                       var attrId = id.replace( runescape, funescape );
+                       return function( elem ) {
+                               var node = typeof elem.getAttributeNode !== "undefined" &&
+                                       elem.getAttributeNode("id");
+                               return node && node.value === attrId;
+                       };
+               };
+
+               // Support: IE 6 - 7 only
+               // getElementById is not reliable as a find shortcut
+               Expr.find["ID"] = function( id, context ) {
+                       if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
+                               var node, i, elems,
+                                       elem = context.getElementById( id );
+
+                               if ( elem ) {
 
-               if ( !cache[ id ] ) {
-                       cache[ id ] = {};
+                                       // Verify the id attribute
+                                       node = elem.getAttributeNode("id");
+                                       if ( node && node.value === id ) {
+                                               return [ elem ];
+                                       }
+
+                                       // Fall back on getElementsByName
+                                       elems = context.getElementsByName( id );
+                                       i = 0;
+                                       while ( (elem = elems[i++]) ) {
+                                               node = elem.getAttributeNode("id");
+                                               if ( node && node.value === id ) {
+                                                       return [ elem ];
+                                               }
+                                       }
+                               }
 
-                       // Avoids exposing jQuery metadata on plain JS objects when the object
-                       // is serialized using JSON.stringify
-                       if ( !isNode ) {
-                               cache[ id ].toJSON = jQuery.noop;
+                               return [];
                        }
-               }
+               };
+       }
 
-               // An object can be passed to jQuery.data instead of a key/value pair; this gets
-               // shallow copied over onto the existing cache
-               if ( typeof name === "object" || typeof name === "function" ) {
-                       if ( pvt ) {
-                               cache[ id ] = jQuery.extend( cache[ id ], name );
-                       } else {
-                               cache[ id ].data = jQuery.extend( cache[ id ].data, name );
+       // Tag
+       Expr.find["TAG"] = support.getElementsByTagName ?
+               function( tag, context ) {
+                       if ( typeof context.getElementsByTagName !== "undefined" ) {
+                               return context.getElementsByTagName( tag );
+
+                       // DocumentFragment nodes don't have gEBTN
+                       } else if ( support.qsa ) {
+                               return context.querySelectorAll( tag );
                        }
-               }
+               } :
+
+               function( tag, context ) {
+                       var elem,
+                               tmp = [],
+                               i = 0,
+                               // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
+                               results = context.getElementsByTagName( tag );
 
-               privateCache = thisCache = cache[ id ];
+                       // Filter out possible comments
+                       if ( tag === "*" ) {
+                               while ( (elem = results[i++]) ) {
+                                       if ( elem.nodeType === 1 ) {
+                                               tmp.push( elem );
+                                       }
+                               }
 
-               // jQuery data() is stored in a separate object inside the object's internal data
-               // cache in order to avoid key collisions between internal data and user-defined
-               // data.
-               if ( !pvt ) {
-                       if ( !thisCache.data ) {
-                               thisCache.data = {};
+                               return tmp;
                        }
+                       return results;
+               };
 
-                       thisCache = thisCache.data;
+       // Class
+       Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
+               if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
+                       return context.getElementsByClassName( className );
                }
+       };
 
-               if ( data !== undefined ) {
-                       thisCache[ jQuery.camelCase( name ) ] = data;
-               }
+       /* QSA/matchesSelector
+       ---------------------------------------------------------------------- */
 
-               // Users should not attempt to inspect the internal events object using jQuery.data,
-               // it is undocumented and subject to change. But does anyone listen? No.
-               if ( isEvents && !thisCache[ name ] ) {
-                       return privateCache.events;
-               }
+       // QSA and matchesSelector support
 
-               // Check for both converted-to-camel and non-converted data property names
-               // If a data property was specified
-               if ( getByName ) {
+       // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+       rbuggyMatches = [];
 
-                       // First Try to find as-is property data
-                       ret = thisCache[ name ];
+       // qSa(:focus) reports false when true (Chrome 21)
+       // We allow this because of a bug in IE8/9 that throws an error
+       // whenever `document.activeElement` is accessed on an iframe
+       // So, we allow :focus to pass through QSA all the time to avoid the IE error
+       // See https://bugs.jquery.com/ticket/13378
+       rbuggyQSA = [];
 
-                       // Test for null|undefined property data
-                       if ( ret == null ) {
+       if ( (support.qsa = rnative.test( document.querySelectorAll )) ) {
+               // Build QSA regex
+               // Regex strategy adopted from Diego Perini
+               assert(function( el ) {
+                       // Select is set to empty string on purpose
+                       // This is to test IE's treatment of not explicitly
+                       // setting a boolean content attribute,
+                       // since its presence should be enough
+                       // https://bugs.jquery.com/ticket/12359
+                       docElem.appendChild( el ).innerHTML = "<a id='" + expando + "'></a>" +
+                               "<select id='" + expando + "-\r\\' msallowcapture=''>" +
+                               "<option selected=''></option></select>";
 
-                               // Try to find the camelCased property
-                               ret = thisCache[ jQuery.camelCase( name ) ];
+                       // Support: IE8, Opera 11-12.16
+                       // Nothing should be selected when empty strings follow ^= or $= or *=
+                       // The test attribute must be unknown in Opera but "safe" for WinRT
+                       // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
+                       if ( el.querySelectorAll("[msallowcapture^='']").length ) {
+                               rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
                        }
-               } else {
-                       ret = thisCache;
-               }
 
-               return ret;
-       },
+                       // Support: IE8
+                       // Boolean attributes and "value" are not treated correctly
+                       if ( !el.querySelectorAll("[selected]").length ) {
+                               rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
+                       }
 
-       removeData: function( elem, name, pvt /* Internal Use Only */ ) {
-               if ( !jQuery.acceptData( elem ) ) {
-                       return;
-               }
+                       // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
+                       if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
+                               rbuggyQSA.push("~=");
+                       }
 
-               var thisCache, i, l,
+                       // Webkit/Opera - :checked should return selected option elements
+                       // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+                       // IE8 throws error here and will not see later tests
+                       if ( !el.querySelectorAll(":checked").length ) {
+                               rbuggyQSA.push(":checked");
+                       }
 
-                       // Reference to internal data cache key
-                       internalKey = jQuery.expando,
+                       // Support: Safari 8+, iOS 8+
+                       // https://bugs.webkit.org/show_bug.cgi?id=136851
+                       // In-page `selector#id sibling-combinator selector` fails
+                       if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) {
+                               rbuggyQSA.push(".#.+[+~]");
+                       }
+               });
 
-                       isNode = elem.nodeType,
+               assert(function( el ) {
+                       el.innerHTML = "<a href='' disabled='disabled'></a>" +
+                               "<select disabled='disabled'><option/></select>";
 
-                       // See jQuery.data for more information
-                       cache = isNode ? jQuery.cache : elem,
+                       // Support: Windows 8 Native Apps
+                       // The type and name attributes are restricted during .innerHTML assignment
+                       var input = document.createElement("input");
+                       input.setAttribute( "type", "hidden" );
+                       el.appendChild( input ).setAttribute( "name", "D" );
 
-                       // See jQuery.data for more information
-                       id = isNode ? elem[ internalKey ] : internalKey;
+                       // Support: IE8
+                       // Enforce case-sensitivity of name attribute
+                       if ( el.querySelectorAll("[name=d]").length ) {
+                               rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
+                       }
 
-               // If there is already no cache entry for this object, there is no
-               // purpose in continuing
-               if ( !cache[ id ] ) {
-                       return;
-               }
+                       // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+                       // IE8 throws error here and will not see later tests
+                       if ( el.querySelectorAll(":enabled").length !== 2 ) {
+                               rbuggyQSA.push( ":enabled", ":disabled" );
+                       }
 
-               if ( name ) {
+                       // Support: IE9-11+
+                       // IE's :disabled selector does not pick up the children of disabled fieldsets
+                       docElem.appendChild( el ).disabled = true;
+                       if ( el.querySelectorAll(":disabled").length !== 2 ) {
+                               rbuggyQSA.push( ":enabled", ":disabled" );
+                       }
 
-                       thisCache = pvt ? cache[ id ] : cache[ id ].data;
+                       // Opera 10-11 does not throw on post-comma invalid pseudos
+                       el.querySelectorAll("*,:x");
+                       rbuggyQSA.push(",.*:");
+               });
+       }
 
-                       if ( thisCache ) {
+       if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
+               docElem.webkitMatchesSelector ||
+               docElem.mozMatchesSelector ||
+               docElem.oMatchesSelector ||
+               docElem.msMatchesSelector) )) ) {
 
-                               // Support array or space separated string names for data keys
-                               if ( !jQuery.isArray( name ) ) {
+               assert(function( el ) {
+                       // Check to see if it's possible to do matchesSelector
+                       // on a disconnected node (IE 9)
+                       support.disconnectedMatch = matches.call( el, "*" );
 
-                                       // try the string as a key before any manipulation
-                                       if ( name in thisCache ) {
-                                               name = [ name ];
-                                       } else {
+                       // This should fail with an exception
+                       // Gecko does not error, returns false instead
+                       matches.call( el, "[s!='']:x" );
+                       rbuggyMatches.push( "!=", pseudos );
+               });
+       }
 
-                                               // split the camel cased version by spaces unless a key with the spaces exists
-                                               name = jQuery.camelCase( name );
-                                               if ( name in thisCache ) {
-                                                       name = [ name ];
-                                               } else {
-                                                       name = name.split( " " );
-                                               }
+       rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
+       rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
+
+       /* Contains
+       ---------------------------------------------------------------------- */
+       hasCompare = rnative.test( docElem.compareDocumentPosition );
+
+       // Element contains another
+       // Purposefully self-exclusive
+       // As in, an element does not contain itself
+       contains = hasCompare || rnative.test( docElem.contains ) ?
+               function( a, b ) {
+                       var adown = a.nodeType === 9 ? a.documentElement : a,
+                               bup = b && b.parentNode;
+                       return a === bup || !!( bup && bup.nodeType === 1 && (
+                               adown.contains ?
+                                       adown.contains( bup ) :
+                                       a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
+                       ));
+               } :
+               function( a, b ) {
+                       if ( b ) {
+                               while ( (b = b.parentNode) ) {
+                                       if ( b === a ) {
+                                               return true;
                                        }
                                }
-
-                               for ( i = 0, l = name.length; i < l; i++ ) {
-                                       delete thisCache[ name[i] ];
-                               }
-
-                               // If there is no data left in the cache, we want to continue
-                               // and let the cache object itself get destroyed
-                               if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
-                                       return;
-                               }
                        }
-               }
+                       return false;
+               };
 
-               // See jQuery.data for more information
-               if ( !pvt ) {
-                       delete cache[ id ].data;
+       /* Sorting
+       ---------------------------------------------------------------------- */
 
-                       // Don't destroy the parent cache unless the internal data object
-                       // had been the only thing left in it
-                       if ( !isEmptyDataObject(cache[ id ]) ) {
-                               return;
-                       }
+       // Document order sorting
+       sortOrder = hasCompare ?
+       function( a, b ) {
+
+               // Flag for duplicate removal
+               if ( a === b ) {
+                       hasDuplicate = true;
+                       return 0;
                }
 
-               // Browsers that fail expando deletion also refuse to delete expandos on
-               // the window, but it will allow it on all other JS objects; other browsers
-               // don't care
-               // Ensure that `cache` is not a window object #10080
-               if ( jQuery.support.deleteExpando || !cache.setInterval ) {
-                       delete cache[ id ];
-               } else {
-                       cache[ id ] = null;
-               }
-
-               // We destroyed the cache and need to eliminate the expando on the node to avoid
-               // false lookups in the cache for entries that no longer exist
-               if ( isNode ) {
-                       // IE does not allow us to delete expando properties from nodes,
-                       // nor does it have a removeAttribute function on Document nodes;
-                       // we must handle all of these cases
-                       if ( jQuery.support.deleteExpando ) {
-                               delete elem[ internalKey ];
-                       } else if ( elem.removeAttribute ) {
-                               elem.removeAttribute( internalKey );
-                       } else {
-                               elem[ internalKey ] = null;
-                       }
+               // Sort on method existence if only one input has compareDocumentPosition
+               var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
+               if ( compare ) {
+                       return compare;
                }
-       },
 
-       // For internal use only.
-       _data: function( elem, name, data ) {
-               return jQuery.data( elem, name, data, true );
-       },
+               // Calculate position if both inputs belong to the same document
+               compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
+                       a.compareDocumentPosition( b ) :
 
-       // A method for determining if a DOM node can handle the data expando
-       acceptData: function( elem ) {
-               if ( elem.nodeName ) {
-                       var match = jQuery.noData[ elem.nodeName.toLowerCase() ];
+                       // Otherwise we know they are disconnected
+                       1;
 
-                       if ( match ) {
-                               return !(match === true || elem.getAttribute("classid") !== match);
+               // Disconnected nodes
+               if ( compare & 1 ||
+                       (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
+
+                       // Choose the first element that is related to our preferred document
+                       if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
+                               return -1;
                        }
+                       if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
+                               return 1;
+                       }
+
+                       // Maintain original order
+                       return sortInput ?
+                               ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
+                               0;
                }
 
-               return true;
-       }
-});
+               return compare & 4 ? -1 : 1;
+       } :
+       function( a, b ) {
+               // Exit early if the nodes are identical
+               if ( a === b ) {
+                       hasDuplicate = true;
+                       return 0;
+               }
 
-jQuery.fn.extend({
-       data: function( key, value ) {
-               var parts, part, attr, name, l,
-                       elem = this[0],
+               var cur,
                        i = 0,
-                       data = null;
+                       aup = a.parentNode,
+                       bup = b.parentNode,
+                       ap = [ a ],
+                       bp = [ b ];
+
+               // Parentless nodes are either documents or disconnected
+               if ( !aup || !bup ) {
+                       return a === document ? -1 :
+                               b === document ? 1 :
+                               aup ? -1 :
+                               bup ? 1 :
+                               sortInput ?
+                               ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
+                               0;
 
-               // Gets all values
-               if ( key === undefined ) {
-                       if ( this.length ) {
-                               data = jQuery.data( elem );
+               // If the nodes are siblings, we can do a quick check
+               } else if ( aup === bup ) {
+                       return siblingCheck( a, b );
+               }
 
-                               if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
-                                       attr = elem.attributes;
-                                       for ( l = attr.length; i < l; i++ ) {
-                                               name = attr[i].name;
+               // Otherwise we need full lists of their ancestors for comparison
+               cur = a;
+               while ( (cur = cur.parentNode) ) {
+                       ap.unshift( cur );
+               }
+               cur = b;
+               while ( (cur = cur.parentNode) ) {
+                       bp.unshift( cur );
+               }
 
-                                               if ( name.indexOf( "data-" ) === 0 ) {
-                                                       name = jQuery.camelCase( name.substring(5) );
+               // Walk down the tree looking for a discrepancy
+               while ( ap[i] === bp[i] ) {
+                       i++;
+               }
 
-                                                       dataAttr( elem, name, data[ name ] );
-                                               }
-                                       }
-                                       jQuery._data( elem, "parsedAttrs", true );
-                               }
-                       }
+               return i ?
+                       // Do a sibling check if the nodes have a common ancestor
+                       siblingCheck( ap[i], bp[i] ) :
 
-                       return data;
-               }
+                       // Otherwise nodes in our document sort first
+                       ap[i] === preferredDoc ? -1 :
+                       bp[i] === preferredDoc ? 1 :
+                       0;
+       };
 
-               // Sets multiple values
-               if ( typeof key === "object" ) {
-                       return this.each(function() {
-                               jQuery.data( this, key );
-                       });
-               }
+       return document;
+};
+
+Sizzle.matches = function( expr, elements ) {
+       return Sizzle( expr, null, null, elements );
+};
 
-               parts = key.split( ".", 2 );
-               parts[1] = parts[1] ? "." + parts[1] : "";
-               part = parts[1] + "!";
+Sizzle.matchesSelector = function( elem, expr ) {
+       // Set document vars if needed
+       if ( ( elem.ownerDocument || elem ) !== document ) {
+               setDocument( elem );
+       }
 
-               return jQuery.access( this, function( value ) {
+       // Make sure that attribute selectors are quoted
+       expr = expr.replace( rattributeQuotes, "='$1']" );
 
-                       if ( value === undefined ) {
-                               data = this.triggerHandler( "getData" + part, [ parts[0] ] );
+       if ( support.matchesSelector && documentIsHTML &&
+               !compilerCache[ expr + " " ] &&
+               ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
+               ( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {
 
-                               // Try to fetch any internally stored data first
-                               if ( data === undefined && elem ) {
-                                       data = jQuery.data( elem, key );
-                                       data = dataAttr( elem, key, data );
-                               }
+               try {
+                       var ret = matches.call( elem, expr );
 
-                               return data === undefined && parts[1] ?
-                                       this.data( parts[0] ) :
-                                       data;
+                       // IE 9's matchesSelector returns false on disconnected nodes
+                       if ( ret || support.disconnectedMatch ||
+                                       // As well, disconnected nodes are said to be in a document
+                                       // fragment in IE 9
+                                       elem.document && elem.document.nodeType !== 11 ) {
+                               return ret;
                        }
+               } catch (e) {}
+       }
 
-                       parts[1] = value;
-                       this.each(function() {
-                               var self = jQuery( this );
+       return Sizzle( expr, document, null, [ elem ] ).length > 0;
+};
 
-                               self.triggerHandler( "setData" + part, parts );
-                               jQuery.data( this, key, value );
-                               self.triggerHandler( "changeData" + part, parts );
-                       });
-               }, null, value, arguments.length > 1, null, false );
-       },
+Sizzle.contains = function( context, elem ) {
+       // Set document vars if needed
+       if ( ( context.ownerDocument || context ) !== document ) {
+               setDocument( context );
+       }
+       return contains( context, elem );
+};
 
-       removeData: function( key ) {
-               return this.each(function() {
-                       jQuery.removeData( this, key );
-               });
+Sizzle.attr = function( elem, name ) {
+       // Set document vars if needed
+       if ( ( elem.ownerDocument || elem ) !== document ) {
+               setDocument( elem );
        }
-});
 
-function dataAttr( elem, key, data ) {
-       // If nothing was found internally, try to fetch any
-       // data from the HTML5 data-* attribute
-       if ( data === undefined && elem.nodeType === 1 ) {
+       var fn = Expr.attrHandle[ name.toLowerCase() ],
+               // Don't get fooled by Object.prototype properties (jQuery #13807)
+               val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
+                       fn( elem, name, !documentIsHTML ) :
+                       undefined;
 
-               var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+       return val !== undefined ?
+               val :
+               support.attributes || !documentIsHTML ?
+                       elem.getAttribute( name ) :
+                       (val = elem.getAttributeNode(name)) && val.specified ?
+                               val.value :
+                               null;
+};
 
-               data = elem.getAttribute( name );
+Sizzle.escape = function( sel ) {
+       return (sel + "").replace( rcssescape, fcssescape );
+};
 
-               if ( typeof data === "string" ) {
-                       try {
-                               data = data === "true" ? true :
-                               data === "false" ? false :
-                               data === "null" ? null :
-                               jQuery.isNumeric( data ) ? +data :
-                                       rbrace.test( data ) ? jQuery.parseJSON( data ) :
-                                       data;
-                       } catch( e ) {}
+Sizzle.error = function( msg ) {
+       throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
 
-                       // Make sure we set the data so it isn't changed later
-                       jQuery.data( elem, key, data );
+/**
+ * Document sorting and removing duplicates
+ * @param {ArrayLike} results
+ */
+Sizzle.uniqueSort = function( results ) {
+       var elem,
+               duplicates = [],
+               j = 0,
+               i = 0;
 
-               } else {
-                       data = undefined;
+       // Unless we *know* we can detect duplicates, assume their presence
+       hasDuplicate = !support.detectDuplicates;
+       sortInput = !support.sortStable && results.slice( 0 );
+       results.sort( sortOrder );
+
+       if ( hasDuplicate ) {
+               while ( (elem = results[i++]) ) {
+                       if ( elem === results[ i ] ) {
+                               j = duplicates.push( i );
+                       }
+               }
+               while ( j-- ) {
+                       results.splice( duplicates[ j ], 1 );
                }
        }
 
-       return data;
-}
+       // Clear input after sorting to release objects
+       // See https://github.com/jquery/sizzle/pull/225
+       sortInput = null;
 
-// checks a cache object for emptiness
-function isEmptyDataObject( obj ) {
-       for ( var name in obj ) {
+       return results;
+};
 
-               // if the public data object is empty, the private is still empty
-               if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
-                       continue;
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+       var node,
+               ret = "",
+               i = 0,
+               nodeType = elem.nodeType;
+
+       if ( !nodeType ) {
+               // If no nodeType, this is expected to be an array
+               while ( (node = elem[i++]) ) {
+                       // Do not traverse comment nodes
+                       ret += getText( node );
                }
-               if ( name !== "toJSON" ) {
-                       return false;
+       } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+               // Use textContent for elements
+               // innerText usage removed for consistency of new lines (jQuery #11153)
+               if ( typeof elem.textContent === "string" ) {
+                       return elem.textContent;
+               } else {
+                       // Traverse its children
+                       for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+                               ret += getText( elem );
+                       }
                }
+       } else if ( nodeType === 3 || nodeType === 4 ) {
+               return elem.nodeValue;
        }
+       // Do not include comment or processing instruction nodes
 
-       return true;
-}
+       return ret;
+};
 
+Expr = Sizzle.selectors = {
 
+       // Can be adjusted by the user
+       cacheLength: 50,
 
+       createPseudo: markFunction,
 
-function handleQueueMarkDefer( elem, type, src ) {
-       var deferDataKey = type + "defer",
-               queueDataKey = type + "queue",
-               markDataKey = type + "mark",
-               defer = jQuery._data( elem, deferDataKey );
-       if ( defer &&
-               ( src === "queue" || !jQuery._data(elem, queueDataKey) ) &&
-               ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) {
-               // Give room for hard-coded callbacks to fire first
-               // and eventually mark/queue something else on the element
-               setTimeout( function() {
-                       if ( !jQuery._data( elem, queueDataKey ) &&
-                               !jQuery._data( elem, markDataKey ) ) {
-                               jQuery.removeData( elem, deferDataKey, true );
-                               defer.fire();
-                       }
-               }, 0 );
-       }
-}
+       match: matchExpr,
 
-jQuery.extend({
+       attrHandle: {},
 
-       _mark: function( elem, type ) {
-               if ( elem ) {
-                       type = ( type || "fx" ) + "mark";
-                       jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 );
-               }
+       find: {},
+
+       relative: {
+               ">": { dir: "parentNode", first: true },
+               " ": { dir: "parentNode" },
+               "+": { dir: "previousSibling", first: true },
+               "~": { dir: "previousSibling" }
        },
 
-       _unmark: function( force, elem, type ) {
-               if ( force !== true ) {
-                       type = elem;
-                       elem = force;
-                       force = false;
-               }
-               if ( elem ) {
-                       type = type || "fx";
-                       var key = type + "mark",
-                               count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 );
-                       if ( count ) {
-                               jQuery._data( elem, key, count );
-                       } else {
-                               jQuery.removeData( elem, key, true );
-                               handleQueueMarkDefer( elem, type, "mark" );
+       preFilter: {
+               "ATTR": function( match ) {
+                       match[1] = match[1].replace( runescape, funescape );
+
+                       // Move the given value to match[3] whether quoted or unquoted
+                       match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
+
+                       if ( match[2] === "~=" ) {
+                               match[3] = " " + match[3] + " ";
                        }
-               }
-       },
 
-       queue: function( elem, type, data ) {
-               var q;
-               if ( elem ) {
-                       type = ( type || "fx" ) + "queue";
-                       q = jQuery._data( elem, type );
+                       return match.slice( 0, 4 );
+               },
 
-                       // Speed up dequeue by getting out quickly if this is just a lookup
-                       if ( data ) {
-                               if ( !q || jQuery.isArray(data) ) {
-                                       q = jQuery._data( elem, type, jQuery.makeArray(data) );
-                               } else {
-                                       q.push( data );
+               "CHILD": function( match ) {
+                       /* matches from matchExpr["CHILD"]
+                               1 type (only|nth|...)
+                               2 what (child|of-type)
+                               3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+                               4 xn-component of xn+y argument ([+-]?\d*n|)
+                               5 sign of xn-component
+                               6 x of xn-component
+                               7 sign of y-component
+                               8 y of y-component
+                       */
+                       match[1] = match[1].toLowerCase();
+
+                       if ( match[1].slice( 0, 3 ) === "nth" ) {
+                               // nth-* requires argument
+                               if ( !match[3] ) {
+                                       Sizzle.error( match[0] );
                                }
+
+                               // numeric x and y parameters for Expr.filter.CHILD
+                               // remember that false/true cast respectively to 0/1
+                               match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
+                               match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
+
+                       // other types prohibit arguments
+                       } else if ( match[3] ) {
+                               Sizzle.error( match[0] );
                        }
-                       return q || [];
-               }
-       },
 
-       dequeue: function( elem, type ) {
-               type = type || "fx";
+                       return match;
+               },
 
-               var queue = jQuery.queue( elem, type ),
-                       fn = queue.shift(),
-                       hooks = {};
+               "PSEUDO": function( match ) {
+                       var excess,
+                               unquoted = !match[6] && match[2];
 
-               // If the fx queue is dequeued, always remove the progress sentinel
-               if ( fn === "inprogress" ) {
-                       fn = queue.shift();
-               }
+                       if ( matchExpr["CHILD"].test( match[0] ) ) {
+                               return null;
+                       }
 
-               if ( fn ) {
-                       // Add a progress sentinel to prevent the fx queue from being
-                       // automatically dequeued
-                       if ( type === "fx" ) {
-                               queue.unshift( "inprogress" );
+                       // Accept quoted arguments as-is
+                       if ( match[3] ) {
+                               match[2] = match[4] || match[5] || "";
+
+                       // Strip excess characters from unquoted arguments
+                       } else if ( unquoted && rpseudo.test( unquoted ) &&
+                               // Get excess from tokenize (recursively)
+                               (excess = tokenize( unquoted, true )) &&
+                               // advance to the next closing parenthesis
+                               (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
+
+                               // excess is a negative index
+                               match[0] = match[0].slice( 0, excess );
+                               match[2] = unquoted.slice( 0, excess );
                        }
 
-                       jQuery._data( elem, type + ".run", hooks );
-                       fn.call( elem, function() {
-                               jQuery.dequeue( elem, type );
-                       }, hooks );
+                       // Return only captures needed by the pseudo filter method (type and argument)
+                       return match.slice( 0, 3 );
                }
+       },
 
-               if ( !queue.length ) {
-                       jQuery.removeData( elem, type + "queue " + type + ".run", true );
-                       handleQueueMarkDefer( elem, type, "queue" );
-               }
-       }
-});
+       filter: {
 
-jQuery.fn.extend({
-       queue: function( type, data ) {
-               var setter = 2;
+               "TAG": function( nodeNameSelector ) {
+                       var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
+                       return nodeNameSelector === "*" ?
+                               function() { return true; } :
+                               function( elem ) {
+                                       return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+                               };
+               },
 
-               if ( typeof type !== "string" ) {
-                       data = type;
-                       type = "fx";
-                       setter--;
-               }
+               "CLASS": function( className ) {
+                       var pattern = classCache[ className + " " ];
 
-               if ( arguments.length < setter ) {
-                       return jQuery.queue( this[0], type );
-               }
+                       return pattern ||
+                               (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
+                               classCache( className, function( elem ) {
+                                       return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" );
+                               });
+               },
 
-               return data === undefined ?
-                       this :
-                       this.each(function() {
-                               var queue = jQuery.queue( this, type, data );
+               "ATTR": function( name, operator, check ) {
+                       return function( elem ) {
+                               var result = Sizzle.attr( elem, name );
 
-                               if ( type === "fx" && queue[0] !== "inprogress" ) {
-                                       jQuery.dequeue( this, type );
+                               if ( result == null ) {
+                                       return operator === "!=";
                                }
-                       });
-       },
-       dequeue: function( type ) {
-               return this.each(function() {
-                       jQuery.dequeue( this, type );
-               });
-       },
-       // Based off of the plugin by Clint Helfers, with permission.
-       // http://blindsignals.com/index.php/2009/07/jquery-delay/
-       delay: function( time, type ) {
-               time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
-               type = type || "fx";
+                               if ( !operator ) {
+                                       return true;
+                               }
+
+                               result += "";
 
-               return this.queue( type, function( next, hooks ) {
-                       var timeout = setTimeout( next, time );
-                       hooks.stop = function() {
-                               clearTimeout( timeout );
+                               return operator === "=" ? result === check :
+                                       operator === "!=" ? result !== check :
+                                       operator === "^=" ? check && result.indexOf( check ) === 0 :
+                                       operator === "*=" ? check && result.indexOf( check ) > -1 :
+                                       operator === "$=" ? check && result.slice( -check.length ) === check :
+                                       operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
+                                       operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
+                                       false;
                        };
-               });
-       },
-       clearQueue: function( type ) {
-               return this.queue( type || "fx", [] );
-       },
-       // Get a promise resolved when queues of a certain type
-       // are emptied (fx is the type by default)
-       promise: function( type, object ) {
-               if ( typeof type !== "string" ) {
-                       object = type;
-                       type = undefined;
-               }
-               type = type || "fx";
-               var defer = jQuery.Deferred(),
-                       elements = this,
-                       i = elements.length,
-                       count = 1,
-                       deferDataKey = type + "defer",
-                       queueDataKey = type + "queue",
-                       markDataKey = type + "mark",
-                       tmp;
-               function resolve() {
-                       if ( !( --count ) ) {
-                               defer.resolveWith( elements, [ elements ] );
-                       }
-               }
-               while( i-- ) {
-                       if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
-                                       ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
-                                               jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
-                                       jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) {
-                               count++;
-                               tmp.add( resolve );
-                       }
-               }
-               resolve();
-               return defer.promise( object );
-       }
-});
+               },
 
+               "CHILD": function( type, what, argument, first, last ) {
+                       var simple = type.slice( 0, 3 ) !== "nth",
+                               forward = type.slice( -4 ) !== "last",
+                               ofType = what === "of-type";
+
+                       return first === 1 && last === 0 ?
+
+                               // Shortcut for :nth-*(n)
+                               function( elem ) {
+                                       return !!elem.parentNode;
+                               } :
+
+                               function( elem, context, xml ) {
+                                       var cache, uniqueCache, outerCache, node, nodeIndex, start,
+                                               dir = simple !== forward ? "nextSibling" : "previousSibling",
+                                               parent = elem.parentNode,
+                                               name = ofType && elem.nodeName.toLowerCase(),
+                                               useCache = !xml && !ofType,
+                                               diff = false;
+
+                                       if ( parent ) {
+
+                                               // :(first|last|only)-(child|of-type)
+                                               if ( simple ) {
+                                                       while ( dir ) {
+                                                               node = elem;
+                                                               while ( (node = node[ dir ]) ) {
+                                                                       if ( ofType ?
+                                                                               node.nodeName.toLowerCase() === name :
+                                                                               node.nodeType === 1 ) {
+
+                                                                               return false;
+                                                                       }
+                                                               }
+                                                               // Reverse direction for :only-* (if we haven't yet done so)
+                                                               start = dir = type === "only" && !start && "nextSibling";
+                                                       }
+                                                       return true;
+                                               }
 
+                                               start = [ forward ? parent.firstChild : parent.lastChild ];
 
+                                               // non-xml :nth-child(...) stores cache data on `parent`
+                                               if ( forward && useCache ) {
 
-var rclass = /[\n\t\r]/g,
-       rspace = /\s+/,
-       rreturn = /\r/g,
-       rtype = /^(?:button|input)$/i,
-       rfocusable = /^(?:button|input|object|select|textarea)$/i,
-       rclickable = /^a(?:rea)?$/i,
-       rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
-       getSetAttribute = jQuery.support.getSetAttribute,
-       nodeHook, boolHook, fixSpecified;
+                                                       // Seek `elem` from a previously-cached index
 
-jQuery.fn.extend({
-       attr: function( name, value ) {
-               return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
-       },
+                                                       // ...in a gzip-friendly way
+                                                       node = parent;
+                                                       outerCache = node[ expando ] || (node[ expando ] = {});
 
-       removeAttr: function( name ) {
-               return this.each(function() {
-                       jQuery.removeAttr( this, name );
-               });
-       },
+                                                       // Support: IE <9 only
+                                                       // Defend against cloned attroperties (jQuery gh-1709)
+                                                       uniqueCache = outerCache[ node.uniqueID ] ||
+                                                               (outerCache[ node.uniqueID ] = {});
 
-       prop: function( name, value ) {
-               return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
-       },
+                                                       cache = uniqueCache[ type ] || [];
+                                                       nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
+                                                       diff = nodeIndex && cache[ 2 ];
+                                                       node = nodeIndex && parent.childNodes[ nodeIndex ];
 
-       removeProp: function( name ) {
-               name = jQuery.propFix[ name ] || name;
-               return this.each(function() {
-                       // try/catch handles cases where IE balks (such as removing a property on window)
-                       try {
-                               this[ name ] = undefined;
-                               delete this[ name ];
-                       } catch( e ) {}
-               });
-       },
+                                                       while ( (node = ++nodeIndex && node && node[ dir ] ||
 
-       addClass: function( value ) {
-               var classNames, i, l, elem,
-                       setClass, c, cl;
+                                                               // Fallback to seeking `elem` from the start
+                                                               (diff = nodeIndex = 0) || start.pop()) ) {
 
-               if ( jQuery.isFunction( value ) ) {
-                       return this.each(function( j ) {
-                               jQuery( this ).addClass( value.call(this, j, this.className) );
-                       });
-               }
+                                                               // When found, cache indexes on `parent` and break
+                                                               if ( node.nodeType === 1 && ++diff && node === elem ) {
+                                                                       uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
+                                                                       break;
+                                                               }
+                                                       }
 
-               if ( value && typeof value === "string" ) {
-                       classNames = value.split( rspace );
+                                               } else {
+                                                       // Use previously-cached element index if available
+                                                       if ( useCache ) {
+                                                               // ...in a gzip-friendly way
+                                                               node = elem;
+                                                               outerCache = node[ expando ] || (node[ expando ] = {});
+
+                                                               // Support: IE <9 only
+                                                               // Defend against cloned attroperties (jQuery gh-1709)
+                                                               uniqueCache = outerCache[ node.uniqueID ] ||
+                                                                       (outerCache[ node.uniqueID ] = {});
+
+                                                               cache = uniqueCache[ type ] || [];
+                                                               nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
+                                                               diff = nodeIndex;
+                                                       }
 
-                       for ( i = 0, l = this.length; i < l; i++ ) {
-                               elem = this[ i ];
+                                                       // xml :nth-child(...)
+                                                       // or :nth-last-child(...) or :nth(-last)?-of-type(...)
+                                                       if ( diff === false ) {
+                                                               // Use the same loop as above to seek `elem` from the start
+                                                               while ( (node = ++nodeIndex && node && node[ dir ] ||
+                                                                       (diff = nodeIndex = 0) || start.pop()) ) {
 
-                               if ( elem.nodeType === 1 ) {
-                                       if ( !elem.className && classNames.length === 1 ) {
-                                               elem.className = value;
+                                                                       if ( ( ofType ?
+                                                                               node.nodeName.toLowerCase() === name :
+                                                                               node.nodeType === 1 ) &&
+                                                                               ++diff ) {
 
-                                       } else {
-                                               setClass = " " + elem.className + " ";
+                                                                               // Cache the index of each encountered element
+                                                                               if ( useCache ) {
+                                                                                       outerCache = node[ expando ] || (node[ expando ] = {});
+
+                                                                                       // Support: IE <9 only
+                                                                                       // Defend against cloned attroperties (jQuery gh-1709)
+                                                                                       uniqueCache = outerCache[ node.uniqueID ] ||
+                                                                                               (outerCache[ node.uniqueID ] = {});
 
-                                               for ( c = 0, cl = classNames.length; c < cl; c++ ) {
-                                                       if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) {
-                                                               setClass += classNames[ c ] + " ";
+                                                                                       uniqueCache[ type ] = [ dirruns, diff ];
+                                                                               }
+
+                                                                               if ( node === elem ) {
+                                                                                       break;
+                                                                               }
+                                                                       }
+                                                               }
                                                        }
                                                }
-                                               elem.className = jQuery.trim( setClass );
-                                       }
-                               }
-                       }
-               }
 
-               return this;
-       },
+                                               // Incorporate the offset, then check against cycle size
+                                               diff -= last;
+                                               return diff === first || ( diff % first === 0 && diff / first >= 0 );
+                                       }
+                               };
+               },
 
-       removeClass: function( value ) {
-               var classNames, i, l, elem, className, c, cl;
+               "PSEUDO": function( pseudo, argument ) {
+                       // pseudo-class names are case-insensitive
+                       // http://www.w3.org/TR/selectors/#pseudo-classes
+                       // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+                       // Remember that setFilters inherits from pseudos
+                       var args,
+                               fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+                                       Sizzle.error( "unsupported pseudo: " + pseudo );
+
+                       // The user may use createPseudo to indicate that
+                       // arguments are needed to create the filter function
+                       // just as Sizzle does
+                       if ( fn[ expando ] ) {
+                               return fn( argument );
+                       }
+
+                       // But maintain support for old signatures
+                       if ( fn.length > 1 ) {
+                               args = [ pseudo, pseudo, "", argument ];
+                               return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+                                       markFunction(function( seed, matches ) {
+                                               var idx,
+                                                       matched = fn( seed, argument ),
+                                                       i = matched.length;
+                                               while ( i-- ) {
+                                                       idx = indexOf( seed, matched[i] );
+                                                       seed[ idx ] = !( matches[ idx ] = matched[i] );
+                                               }
+                                       }) :
+                                       function( elem ) {
+                                               return fn( elem, 0, args );
+                                       };
+                       }
 
-               if ( jQuery.isFunction( value ) ) {
-                       return this.each(function( j ) {
-                               jQuery( this ).removeClass( value.call(this, j, this.className) );
-                       });
+                       return fn;
                }
+       },
 
-               if ( (value && typeof value === "string") || value === undefined ) {
-                       classNames = ( value || "" ).split( rspace );
+       pseudos: {
+               // Potentially complex pseudos
+               "not": markFunction(function( selector ) {
+                       // Trim the selector passed to compile
+                       // to avoid treating leading and trailing
+                       // spaces as combinators
+                       var input = [],
+                               results = [],
+                               matcher = compile( selector.replace( rtrim, "$1" ) );
 
-                       for ( i = 0, l = this.length; i < l; i++ ) {
-                               elem = this[ i ];
+                       return matcher[ expando ] ?
+                               markFunction(function( seed, matches, context, xml ) {
+                                       var elem,
+                                               unmatched = matcher( seed, null, xml, [] ),
+                                               i = seed.length;
 
-                               if ( elem.nodeType === 1 && elem.className ) {
-                                       if ( value ) {
-                                               className = (" " + elem.className + " ").replace( rclass, " " );
-                                               for ( c = 0, cl = classNames.length; c < cl; c++ ) {
-                                                       className = className.replace(" " + classNames[ c ] + " ", " ");
+                                       // Match elements unmatched by `matcher`
+                                       while ( i-- ) {
+                                               if ( (elem = unmatched[i]) ) {
+                                                       seed[i] = !(matches[i] = elem);
                                                }
-                                               elem.className = jQuery.trim( className );
-
-                                       } else {
-                                               elem.className = "";
                                        }
-                               }
-                       }
-               }
+                               }) :
+                               function( elem, context, xml ) {
+                                       input[0] = elem;
+                                       matcher( input, null, xml, results );
+                                       // Don't keep the element (issue #299)
+                                       input[0] = null;
+                                       return !results.pop();
+                               };
+               }),
 
-               return this;
-       },
+               "has": markFunction(function( selector ) {
+                       return function( elem ) {
+                               return Sizzle( selector, elem ).length > 0;
+                       };
+               }),
 
-       toggleClass: function( value, stateVal ) {
-               var type = typeof value,
-                       isBool = typeof stateVal === "boolean";
+               "contains": markFunction(function( text ) {
+                       text = text.replace( runescape, funescape );
+                       return function( elem ) {
+                               return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
+                       };
+               }),
+
+               // "Whether an element is represented by a :lang() selector
+               // is based solely on the element's language value
+               // being equal to the identifier C,
+               // or beginning with the identifier C immediately followed by "-".
+               // The matching of C against the element's language value is performed case-insensitively.
+               // The identifier C does not have to be a valid language name."
+               // http://www.w3.org/TR/selectors/#lang-pseudo
+               "lang": markFunction( function( lang ) {
+                       // lang value must be a valid identifier
+                       if ( !ridentifier.test(lang || "") ) {
+                               Sizzle.error( "unsupported lang: " + lang );
+                       }
+                       lang = lang.replace( runescape, funescape ).toLowerCase();
+                       return fun